This document is the summary of the Introduction to R workshop.

All correspondence related to this document should be addressed to:

Omid Ghasemi (Macquarie University, Sydney, NSW, 2109, AUSTRALIA)

Email:

1 Research Question

The aim of the study is to test if simple arguments are more effective in belief revision than more complex arguments. To that end, we present participants with an imaginary scenario (two alien creatures on a planet) and a theory (one creature is predator and the other one is prey) and we ask them to rate the likelihood truth of the theory based on a simple fact (We adapted this method from Gregg et al.,2017; see the original study here). Then, in a between-subject manipulation, participants will be presented with either 6 simple arguments (Modus Ponens conditionals) or 6 more complex arguments (Modus Tollens conditionals), and they will be asked to rate the likelihood truth of the initial theory on 7 stages.

The first stage is the base rating stage. The next three stages include supportive arguments of the theory and the last three arguments include disproving arguments of the theory. We hypothesized that the group with simple arguments shows better persuasion (as it reflects in higher ratings for the supportive arguments) and better dissuasion (as it reflects in lower ratings for the opposing arguments).

In the last part of the study, participants will be asked to answer several cognitive capacity/style measures including thinking style (CRT), open-mindedness (AOT-E), reasoning ability (mindware), and numeracy scales. We hypothesized that cognitive ability, cognitive style, and open-mindedness are positive predictors of persuasion and dissuasion. These associations should be more pronounced for participants in the group with complex arguments because the ability and willingness to engage in deliberative thinking may favor participants to assess the underlying logical structure of those arguments. However, for participants in the simple group, the logical structure of arguments is more evident, so participants with lower ability can still assess the logical status of those arguments.

Thus, our hypotheses for this experiment are as follows:

  • Participants in the group with simple arguments have higher ratings for supportive arguments (They are more easily persuaded than those in the group with complex arguments).

  • Participants in the group with simple arguments have lower ratings for opposing arguments (They are more easily dissuaded than those in the group with complex arguments).

  • There are significant associations between thinking style (CRT), open-mindedness (AOT-E), reasoning ability (mindware), and numeracy scales with both persuasion and dissuasion indexes in each group and in the entire sample. The relationship between these measures should be stronger, although not significantly, for participants in the group with complex arguments.

2 Getting Ready

First, we need to design the experiment. For this experiment, we use online platforms for data collection. There are several options such as Gorilla, JSpsych, Qualtrics, psychoJS (pavlovia), etc. Since we do not need any reaction time data, we simply use Qualtrics. For an overview of different lab-based and online platforms, see here.

Next, we need to decide on the number of participants (sample size). For this study, we do not sue power analysis since we cannot access more than 120 participants. However, it is highly suggested calculate sample size using power estimation. You can find some nice tutorials on how to do that here, here, and here.

After we created the experiment and decided on the sample size, the next step is to preresigter the study. However, it would be better to do a pilot with 4 or 5 participants, clean all the data, do the desired analysis, and then pre-register the analysis and those codes. You can find the preregistration form for the current study here.

Finally, we need to restructure our project in a tidy folder with different sub-folders. Having a clean and tidy folder structure can save us! There are different formats of folder structure (for example, see here and here), but for now, we use the following structure:

3 Introduction to R

# load libraries
library(tidyverse)
library(here)
library(janitor)
library(broom)
library(afex)
library(emmeans)
library(knitr)
library(kableExtra)
library(ggsci)
library(patchwork)
library(skimr)
# install.packages("devtools")
# devtools::install_github("easystats/correlation")
library("correlation")
options(scipen=999) # turn off scientific notations
options(contrasts = c('contr.sum','contr.poly')) # set the contrast sum globally 
options(knitr.kable.NA = '')

R can be used as a calculator. For mathematical purposes, be careful of the order in which R executes the commands.

10 + 10
## [1] 20
4 ^ 2
## [1] 16
(250 / 500) * 100
## [1] 50

R is a bit flexible with spacing (but no spacing in the name of variables and words)

10+10
## [1] 20
10                 +           10
## [1] 20

R can sometimes tell that you’re not finished yet

10 +

How to create a variable? Variable assignment using <- and =. Note that R is case sensitive for everything

pay <- 250

month = 12

pay * month
## [1] 3000
salary <- pay * month

Few points in naming variables and vectors: use short, informative words, keep same method (e.g., not using capital words, use only _ or . ).

3.1 Function

Function is a set of statements combined together to perform a specific task. When we use a block of code repeatedly, we can convert it to a function. To write a function, first, you need to define it:

my_multiplier <- function(a,b){
  result = a * b
  return (result)
}

This code do nothing. To get a result, you need to call it:

my_multiplier (a=2, b=4)
## [1] 8
# or: my_multiplier (2, 4)

We can set a default value for our arguments:

my_multiplier2 <- function(a,b=4){
  result = a * b
  return (result)
}

my_multiplier2 (a=2)
## [1] 8
# or: my_multiplier (2)
# or: my_multiplier (2, 6)

Fortunately, you do not need to write everything from scratch. R has lots of built-in functions that you can use:

round(54.6787)
## [1] 55
round(54.5787, digits = 2)
## [1] 54.58

Use ? before the function name to get some help. For example, ?round. You will see many functions in the rest of the workshop.

3.2 Basic Data Types in R:

function class() is used to show what is the type of a variable.

  1. Logical: TRUE, FALSE can be abbreviated as T, F. They has to be capital, ‘true’ is not a logical data:
class(TRUE)
## [1] "logical"
class(F)
## [1] "logical"
  1. Numeric: all numbers e.g. 5, 10.5, 11,37; a special type of numeric is “integer” which is numbers without decimal. Integers are always numeric, but numeric is not always integer:
class(2)
## [1] "numeric"
class(13.46)
## [1] "numeric"
  1. Character: text for example, “I love R” or “4” or “4.5”:
class("ha ha ha ha")
## [1] "character"
class("56.6")
## [1] "character"
class("TRUE")
## [1] "character"

Can we change the type of data in a variable? Yes, you need to use the function as.---()

as.numeric(TRUE)
## [1] 1
as.character(4)
## [1] "4"
as.numeric("4.5")
## [1] 4.5
as.numeric("Hello")
## Warning: NAs introduced by coercion
## [1] NA

3.3 Data Structures in R

Vector: when there are more than one number or letter stored. Use the combine function c() for that.

sale <- c(1, 2, 3,4, 5, 6, 7, 8, 9, 10) # also sale <- c(1:10)

sale <- c(1:10)

sale * sale
##  [1]   1   4   9  16  25  36  49  64  81 100

Subsetting a vector:

days <- c("Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday")

days[2]
## [1] "Sunday"
days[-2]
## [1] "Saturday"  "Monday"    "Tuesday"   "Wednesday" "Thursday"  "Friday"
days[c(2, 3, 4)]
## [1] "Sunday"  "Monday"  "Tuesday"

3.3.1 Exercise

Create a vector named my_vector with numbers from 0 to 1000 in it:

my_vector <- (0:1000)

mean(my_vector)
## [1] 500
median(my_vector)
## [1] 500
min(my_vector)
## [1] 0
range(my_vector)
## [1]    0 1000
class(my_vector)
## [1] "integer"
sum(my_vector)
## [1] 500500
sd(my_vector)
## [1] 289.1081

List: allows you to gather a variety of objects under one name (that is, the name of the list) in an ordered way. These objects can be matrices, vectors, data frames, even other list.

my_list = list(sale, 1, 3, 4:7, "HELLO", "hello", FALSE)
my_list
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## [[2]]
## [1] 1
## 
## [[3]]
## [1] 3
## 
## [[4]]
## [1] 4 5 6 7
## 
## [[5]]
## [1] "HELLO"
## 
## [[6]]
## [1] "hello"
## 
## [[7]]
## [1] FALSE

Factor: Factors store the vector along with the distinct values of the elements in the vector as labels. The labels are always character irrespective of whether it is numeric or character. For example, variable gender with “male” and “female” entries:

gender <- c("male", "male", "male", " female", "female", "female")
gender <- factor(gender)

R now treats gender as a nominal (categorical) variable: 1=female, 2=male internally (alphabetically).

summary(gender)
##  female  female    male 
##       1       2       3

Question: why when we ran the above function i.e. summary(), it showed three and not two levels of the data? Hint: run ‘gender’.

gender
## [1] male    male    male     female female  female 
## Levels:  female female male

So, be careful of spaces!

3.3.2 Exercise

Create a gender factor with 30 male and 40 females (Hint: use the rep() function):

gender <- c(rep("male",30), rep("female", 40))
gender <- factor(gender)
gender
##  [1] male   male   male   male   male   male   male   male   male   male  
## [11] male   male   male   male   male   male   male   male   male   male  
## [21] male   male   male   male   male   male   male   male   male   male  
## [31] female female female female female female female female female female
## [41] female female female female female female female female female female
## [51] female female female female female female female female female female
## [61] female female female female female female female female female female
## Levels: female male

There are two types of categorical variables: nominal and ordinal. How to create ordered factors (when the variable is nominal and values can be ordered)? We should add two additional arguments to the factor() function: ordered = TRUE, and levels = c("level1", "level2"). For example, we have a vector that shows participants’ education level.

edu<-c(3,2,3,4,1,2,2,3,4)

education<-factor(edu, ordered = TRUE)
levels(education) <- c("Primary school","high school","College","Uni graduated")
education
## [1] College        high school    College        Uni graduated 
## [5] Primary school high school    high school    College       
## [9] Uni graduated 
## Levels: Primary school < high school < College < Uni graduated

3.3.3 Exercise

We have a factor with patient and control values. Here, the first level is control and the second level is patient. Change the order of levels, so patient would be the first level:

health_status <- factor(c(rep('patient',5),rep('control',5)))
health_status
##  [1] patient patient patient patient patient control control control
##  [9] control control
## Levels: control patient
health_status_reordered <- factor(health_status, levels = c('patient','control'))
health_status_reordered
##  [1] patient patient patient patient patient control control control
##  [9] control control
## Levels: patient control

Finally, can you relabel both levels to uppercase characters? (Hint: check ?factor)

health_status_relabeled <- factor(health_status, levels = c('patient','control'), labels = c('Patient','Control'))
health_status_relabeled
##  [1] Patient Patient Patient Patient Patient Control Control Control
##  [9] Control Control
## Levels: Patient Control

Matrices: All columns in a matrix must have the same mode(numeric, character, etc.) and the same length. It can be created using a vector input to the matrix function.

my_matrix = matrix(c(1,2,3,4,5,6,7,8,9), nrow = 3, ncol = 3)

my_matrix
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9

Data frames: (two-dimensional objects) can hold numeric, character or logical values. Within a column all elements have the same data type, but different columns can be of different data type. Let’s create a dataframe:

id <- 1:200
group <- c(rep("Psychotherapy", 100), rep("Medication", 100))
response <- c(rnorm(100, mean = 30, sd = 5),
             rnorm(100, mean = 25, sd = 5))

my_dataframe <-data.frame(Patient = id,
                          Treatment = group,
                          Response = response)

We also could have done the below

my_dataframe <-data.frame(Patient = c(1:200),
                          Treatment = c(rep("Psychotherapy", 100), rep("Medication", 100)),
                          Response = c(rnorm(100, mean = 30, sd = 5),
                                       rnorm(100, mean = 25, sd = 5)))

In large data sets, the function head() enables you to show the first observations of a data frames. Similarly, the function tail() prints out the last observations in your data set.

head(my_dataframe) 
tail(my_dataframe)
Patient Treatment Response
1 Psychotherapy 31.46027
2 Psychotherapy 25.80691
3 Psychotherapy 23.90582
4 Psychotherapy 35.24277
5 Psychotherapy 36.12894
6 Psychotherapy 28.88709
Patient Treatment Response
195 195 Medication 29.98481
196 196 Medication 17.56606
197 197 Medication 27.15201
198 198 Medication 25.47396
199 199 Medication 25.41576
200 200 Medication 26.85049

Similar to vectors and matrices, brackets [] are used to selects data from rows and columns in data.frames:

my_dataframe[35, 3]
## [1] 24.10207

3.3.4 Exercise

How can we get all columns, but only for the first 10 participants?

my_dataframe[1:10, ]
Patient Treatment Response
1 Psychotherapy 31.46027
2 Psychotherapy 25.80691
3 Psychotherapy 23.90582
4 Psychotherapy 35.24277
5 Psychotherapy 36.12894
6 Psychotherapy 28.88709
7 Psychotherapy 28.13632
8 Psychotherapy 26.74151
9 Psychotherapy 28.07995
10 Psychotherapy 25.66144

How to get only the Response column for all participants?

my_dataframe[ , 3]
##   [1] 31.46027 25.80691 23.90582 35.24277 36.12894 28.88709 28.13632
##   [8] 26.74151 28.07995 25.66144 32.43043 32.90031 28.22010 20.49055
##  [15] 21.60086 29.88247 28.37732 28.33941 32.99115 35.60892 28.20174
##  [22] 31.02228 37.67104 26.73629 23.17044 29.62874 27.47495 29.36538
##  [29] 36.66284 37.21628 33.22692 28.58497 29.40086 30.05996 24.10207
##  [36] 37.68405 34.11073 35.26914 35.77968 23.37928 29.54027 26.18844
##  [43] 38.75336 29.88913 35.19795 32.72946 29.27546 31.04248 33.29102
##  [50] 18.01849 29.91320 30.06106 30.93769 29.09398 31.92382 31.01322
##  [57] 26.27603 28.00506 29.75021 32.14493 24.69866 31.15726 22.59687
##  [64] 33.51499 20.87766 24.72480 28.88959 23.23752 22.79437 25.97967
##  [71] 40.90827 30.38728 38.08255 37.16809 25.73616 25.32099 28.77482
##  [78] 34.21075 33.13974 29.55064 23.93372 30.95174 28.30632 37.92416
##  [85] 27.14505 19.64008 34.20583 44.02146 29.18339 35.25485 39.78779
##  [92] 32.02400 33.92133 31.74780 22.73999 31.02149 24.51421 28.80851
##  [99] 37.00935 39.01414 24.46241 33.60924 26.14423 19.96034 24.18702
## [106] 25.42803 26.15863 29.76837 25.03232 25.53612 26.98493 23.44438
## [113] 14.90449 28.02894 24.57431 22.30127 34.10020 20.91610 33.11796
## [120] 37.12811 22.89906 31.94684 27.52520 22.31867 13.92906 19.25865
## [127] 30.37195 24.67580 26.37599 24.65865 28.30528 23.66096 17.49513
## [134] 23.04172 15.84645 18.23439 26.63121 29.81582 32.55382 25.66231
## [141] 28.64869 23.77102 32.00628 25.16474 32.48781 25.98615 22.57022
## [148] 19.36977 28.48540 26.29446 21.81714 24.45360 17.95169 23.09270
## [155] 21.38275 27.08464 18.66920 27.60698 27.70646 24.17864 22.87044
## [162] 24.70419 19.10310 21.52611 25.94191 26.26336 27.21419 26.85767
## [169] 17.14670 24.41177 31.19198 24.97077 24.81557 21.71635 26.72816
## [176] 24.91654 28.13910 21.55515 19.29760 26.87387 23.21848 26.19222
## [183] 25.00059 33.82250 27.32508 35.48514 32.61955 32.35353 10.76799
## [190] 15.55515 23.96873 23.10777 26.09092 21.18117 29.98481 17.56606
## [197] 27.15201 25.47396 25.41576 26.85049

Another easier way for selecting particular items is using their names that is more helpful than number of the rows in large data sets:

my_dataframe[ , "Response"]
# OR:
my_dataframe$Response

4 Data Cleaning

Now, suppose we tested 141 students. First, let’s read and check the uncleaned data:

# read the raw data
raw_data <- read_csv(here("raw_data","raw_data_exp1.csv"))
head(raw_data)
end_date status ip_address progress duration_in_seconds subject recorded_date response_id location_latitude location_longitude distribution_channel user_language consent_form age gender stage1_simple stage2_simple stage3_simple stage4_simple stage5_simple stage6_simple stage7_simple stage1_complex stage2_complex stage3_complex stage4_complex stage5_complex stage6_complex stage7_complex thinking1 thinking2 thinking3 openminded1 openminded2 openminded3 openminded4 openminded5 openminded6 openminded7 openminded8 group numeracy_total reasoning_total
24/9/20 22:02 IP Address 202.7.193.64 100 1517 subj1 24/9/20 22:02 R_1f298znjmVzcOjp -33.85910 151.2002 anonymous EN I consent 18 Female 36 70 68 54 51 43 41 8 50 20 5 5 5 5 5 6 5 3 Complex 9 9
25/9/20 3:23 IP Address 220.245.220.94 100 1131 subj2 25/9/20 3:23 R_tL0A9P33Gi18I0N -34.03680 150.6672 anonymous EN I consent 18 Male 50 55 55 90 75 50 35 8 10 39 6 6 6 5 6 6 5 6 Simple 9 10
27/9/20 22:59 IP Address 121.210.0.211 100 709 subj3 27/9/20 22:59 R_1LNyJhCKxTAAMOW -33.85910 151.2002 anonymous EN I consent 19 Female 50 50 77 60 25 20 13 8 50 20 6 5 4 5 5 6 5 6 Simple 10 8
27/9/20 23:18 IP Address 58.179.100.109 100 949 subj4 27/9/20 23:18 R_3enxzUsEYgs5r1a -12.63921 141.8741 anonymous EN I consent 27 Female 70 80 90 95 70 80 90 8 50 20 6 6 6 1 6 6 6 1 Complex 8 7
28/9/20 0:45 IP Address 120.154.53.68 100 1097 subj5 28/9/20 0:45 R_2Qzl2096a4KNE29 -33.85910 151.2002 anonymous EN I consent 19 Male 71 73 85 95 95 32 32 4 10 39 6 6 5 5 6 6 6 6 Simple 11 11
28/9/20 2:20 IP Address 1.129.107.6 100 880 subj6 28/9/20 2:20 R_esb71WOTQySjusF -33.85910 151.2002 anonymous EN I consent 20 Female 89 100 44 55 100 50 55 8 50 20 6 6 6 5 6 6 6 6 Complex 10 10

4.0.1 Exercise

There is a dataset in the cleaned_data folder named unicef_u5mr.csv. Read the dataset using read_csv and here.

unicef_data <- read_csv(here("cleaned_data","unicef_u5mr.csv"))

In order to clean the data, we use tidyverse which is a collection of packages to work with data. One of the tidyverse packages that we use regularly is dplyr which includes several functions:

  • mutate() adds new variables or change existing ones.
  • select() pick variables (columns) based on their names.
  • filter() picks cases (rows) based on their values.
  • summarise() gives a single single summary of the data (e.g., mean, counts, etc.)
  • arrange() changes the ordering of the rows.
  • group_by() divides your dataframe into grouped dataframes and allow you to do each of the above operations (except for arrange) on every one of them separately.

Pick subject, age, and gender columns:

selected_data <- select(raw_data, subject, age, gender)

Now, do the following tasks: pick all the male participants, pick all the male participants or those greater than 25 years old, and finally pick all male participants and those greater than 25 years old:

# filter all males
filtered_data_male <- filter(raw_data, gender == "Male")
# filter males and older than 25
filtered_data_male_and_greater25 <- filter(raw_data, gender == "Male" & age > 25 )
# filter males or older than 25
filtered_data_male_or_greater25 <- filter(raw_data, gender == "Male" | age > 25 )

Arrange (order) your dataframe based on the age, once in an ascending order (youngers first) and once based on descending order (olders first):

# order participants based on their age
arranged_data <- arrange(raw_data, age)
# order participants based on their age (descendeing)
arranged_data_descending <- arrange(raw_data, desc(age))

Create a column to show if the participant has finished the task or not:

mutated_data <- mutate (raw_data, finished= case_when(progress==100~ "Yes",T~ "No"))

Summarize participants age and sd:

summarise(raw_data, mean= mean(age, na.rm=T),
          sd= sd (age, na.rm=T))
mean sd
21.27273 6.635655

A new function: pipe operators %>% pipes a value into the next function:

raw_data %>% 
  summarise(., mean= mean(age, na.rm=T),
            sd= sd (age, na.rm=T))
mean sd
21.27273 6.635655
raw_data %>% 
  summarise(mean= mean(age, na.rm=T),
            sd= sd (age, na.rm=T))
mean sd
21.27273 6.635655

Calculate the age mean of younger than 25 participants only:

raw_data %>% 
  filter (age < 25) %>%
  summarise(mean= mean(age, na.rm=T),
            sd= sd (age, na.rm=T))
mean sd
19.1913 1.515393

Calculate the age mean of younger than 25 participants for each gender separately:

raw_data %>% 
  filter (age < 25) %>%
  group_by(gender) %>%
  summarise(mean= mean(age, na.rm=T),
            sd= sd (age, na.rm=T)) %>%
  ungroup ()
gender mean sd
Female 19.21053 1.556693
Male 19.10000 1.333772

4.0.2 Exercise

  1. Create a column to show if participant is older than 23 or not and then calculate reasoning ability (reasoning_total) mean for each group separately:
raw_data %>%
  mutate(age_group = case_when(age > 23 ~ "greater than 23", T~ "younger than 23")) %>%
  group_by(age_group) %>%
  summarise(reasoning_total = mean(reasoning_total, na.rm=T))
age_group reasoning_total
greater than 23 8.800000
younger than 23 7.842975
  1. Add the open_mindedness total score (sum) to the dataframe and then convert subject column to factor:
mutated_openmind_data <- raw_data %>%
  mutate(openminded_total= openminded1+openminded2+openminded3+openminded4+openminded5+openminded6+openminded7+openminded8) %>%
  mutate(subject= factor(subject))

Next, we want to pivot our data to switch between long and wide format:

# pivoting your data


# Make you data long
long_data <- raw_data %>%
  select(subject, stage1_simple:stage7_simple,stage1_complex:stage7_complex) %>%
  pivot_longer(cols = c(stage1_simple:stage7_complex), names_to = 'stage', values_to = 'truth_estimate')


# Make you data wide
wide_data <- long_data %>%
  pivot_wider(names_from = stage, values_from= truth_estimate)

4.0.3 Exercise

Convert the UNICEF dataset to long and wide formats:

unicef_data <- read_csv(here("cleaned_data","unicef_u5mr.csv"))

library(janitor)
unicef_data_cleaned <- unicef_data %>%
  clean_names()

unicef_long_data <- unicef_data_cleaned %>% pivot_longer(cols = c(u5mr_1950:u5mr_2015), names_to = 'year', values_to = 'u5mr')
unicef_wideg_data <- unicef_long_data %>% pivot_wider(names_from = 'year', values_from = 'u5mr')

Note: The codes for the previous exercise were taken from this blog post written by Simon Ejdemyr.

Now, let’s do some cleaning using dplyr, tidyr and other tidyverse libraries:

cleaned_data <- raw_data %>% 
  filter(progress == 100) %>% # filter out unfinished participants
  select(-end_date, -status,-ip_address, -duration_in_seconds, -recorded_date:-user_language) %>% #remove some useless columns
  mutate(openminded_total= openminded1+openminded2+openminded3+openminded4+openminded5+openminded6+openminded7+openminded8) %>%# create a total score for our questionnaire
  mutate(thinking1= case_when(thinking1==4~ 1,T~0),
         thinking2= case_when(thinking2==10~ 1,T~0),
         thinking3= case_when(thinking3==39~ 1,T~0),
         thinking_total= thinking1 + thinking2 + thinking3) %>%
  select(-thinking1:-openminded8) %>%
  pivot_longer(cols = c(stage1_simple:stage7_simple,stage1_complex:stage7_complex),names_to = 'stage',values_to = 'truth_estimate') %>% # make our dataframe long
  #pivot_wider(names_from = stage, values_from= truth_estimate) # this code change our dataframe back to wide
  filter(!is.na(truth_estimate)) %>% #remove rows with truth_estimate == NA
  mutate(stage= gsub("_.*", "", stage)) %>%
  rename(consent= consent_form) # rename a column
progress subject consent age gender group numeracy_total reasoning_total openminded_total thinking_total stage truth_estimate
100 subj1 I consent 18 Female Complex 9 9 39 0 stage1 36
100 subj1 I consent 18 Female Complex 9 9 39 0 stage2 70
100 subj1 I consent 18 Female Complex 9 9 39 0 stage3 68
100 subj1 I consent 18 Female Complex 9 9 39 0 stage4 54
100 subj1 I consent 18 Female Complex 9 9 39 0 stage5 51
100 subj1 I consent 18 Female Complex 9 9 39 0 stage6 43

Ok, now the data is clean and tidy which means:

  1. Each variable forms a column.
  2. Each observation forms a row.
  3. Each type of observational unit forms a table (Wickham, 2014).

Check the dataframe and all the data types:

str(cleaned_data)
## tibble [917 × 12] (S3: tbl_df/tbl/data.frame)
##  $ progress        : num [1:917] 100 100 100 100 100 100 100 100 100 100 ...
##  $ subject         : chr [1:917] "subj1" "subj1" "subj1" "subj1" ...
##  $ consent         : chr [1:917] "I consent" "I consent" "I consent" "I consent" ...
##  $ age             : num [1:917] 18 18 18 18 18 18 18 18 18 18 ...
##  $ gender          : chr [1:917] "Female" "Female" "Female" "Female" ...
##  $ group           : chr [1:917] "Complex" "Complex" "Complex" "Complex" ...
##  $ numeracy_total  : num [1:917] 9 9 9 9 9 9 9 9 9 9 ...
##  $ reasoning_total : num [1:917] 9 9 9 9 9 9 9 10 10 10 ...
##  $ openminded_total: num [1:917] 39 39 39 39 39 39 39 46 46 46 ...
##  $ thinking_total  : num [1:917] 0 0 0 0 0 0 0 2 2 2 ...
##  $ stage           : chr [1:917] "stage1" "stage2" "stage3" "stage4" ...
##  $ truth_estimate  : num [1:917] 36 70 68 54 51 43 41 50 55 55 ...

Finally, we save our data to the cleaned_data folder.

write_csv(cleaned_data, here("cleaned_data","cleaned_data_exp1.csv"))

5 Descriptive Statistics

Note: All the data that we use here is manipulated (fabricated) for teaching purpuses. In our study, we failed to find such beautiful and interesting results.

Now, let’s do some descriptive statistics. Now, we can open a new script called data_analysis.r and read some datasets. Then we use skimr package to describe our data.

narcissism_data <- read_csv(here("cleaned_data","narcissism_data.csv"))
narcissism_data %>% skimr::skim()
Data summary
Name Piped data
Number of rows 131
Number of columns 5
_______________________
Column type frequency:
character 1
numeric 4
________________________
Group variables

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
subject 0 1 5 7 0 131 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
psychopathy 0 1 8.78 2.27 0 8.0 10 10 11 ▁▁▁▂▇
self_esteem 0 1 8.45 1.68 4 8.0 8 9 12 ▁▅▇▆▃
narcissism 0 1 38.20 6.15 19 33.5 39 43 48 ▁▂▇▇▆
mental_health 0 1 3.19 1.04 1 3.0 4 4 4 ▂▂▁▃▇

5.0.1 Exercise

  1. Open the dataset called treatment_data.csv in the cleaned_data folder and do a descriptive analysis:
treatment_data <- read_csv(here("cleaned_data","treatment_data.csv"))
treatment_data %>% skimr::skim()
Data summary
Name Piped data
Number of rows 131
Number of columns 7
_______________________
Column type frequency:
character 3
numeric 4
________________________
Group variables

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
subject 0 1 5 7 0 131 0
gender 0 1 4 6 0 2 0
treatment 0 1 3 13 0 2 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
age 0 1 21.15 6.52 16 18.0 19 20.0 63 ▇▁▁▁▁
anxiety 0 1 62.35 24.51 0 40.0 69 81.0 100 ▂▆▃▇▆
depression 0 1 52.50 22.12 0 34.5 51 71.0 100 ▂▇▇▆▃
life_satisfaction 0 1 41.02 23.93 0 21.0 39 56.5 100 ▅▇▅▃▂
  1. Do the same thing for the memory_data.csv.
memory_data <- read_csv(here("cleaned_data","memory_data.csv"))
memory_data %>% group_by(time) %>%
  skimr::skim()
Data summary
Name Piped data
Number of rows 262
Number of columns 5
_______________________
Column type frequency:
character 2
numeric 2
________________________
Group variables time

Variable type: character

skim_variable time n_missing complete_rate min max empty n_unique whitespace
subject post_test_memory 0 1 5 7 0 131 0
subject pre_test_memory 0 1 5 7 0 131 0
gender post_test_memory 0 1 4 6 0 2 0
gender pre_test_memory 0 1 4 6 0 2 0

Variable type: numeric

skim_variable time n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
age post_test_memory 0 1 21.15 6.52 16 18.0 19 20.0 63 ▇▁▁▁▁
age pre_test_memory 0 1 21.15 6.52 16 18.0 19 20.0 63 ▇▁▁▁▁
memory_score post_test_memory 0 1 52.50 22.12 0 34.5 51 71.0 100 ▂▇▇▆▃
memory_score pre_test_memory 0 1 41.02 23.93 0 21.0 39 56.5 100 ▅▇▅▃▂

Now, let’s describe our experiment data. Be careful, we need some data reshaping before description:

data_exp1_orig <- read_csv(here("cleaned_data","cleaned_data_exp1.csv"))


data_exp1 <- data_exp1_orig%>% 
  #mutate_if(is.character, factor) %>%
  mutate(subject= factor(subject), # convert all characters to factor
         group = factor(group),
         stage = factor(stage))

How many participants in total?

data_exp1 %>% summarise(n= n_distinct(subject))
n
131

how many participants in each group?

data_exp1 %>% 
  group_by(subject) %>% 
  filter(row_number()==1) %>% 
  ungroup () %>% 
  group_by(group) %>% 
  count() 
group n
Complex 65
Simple 66

Find the mean and sd for numeric variables using base R summary function:

data_exp1 %>% 
  group_by(subject) %>% 
  filter(row_number()==1) %>% 
  ungroup () %>%
  summary()
##     progress      subject      consent               age       
##  Min.   :100   subj1  :  1   Length:131         Min.   :16.00  
##  1st Qu.:100   subj10 :  1   Class :character   1st Qu.:18.00  
##  Median :100   subj101:  1   Mode  :character   Median :19.00  
##  Mean   :100   subj102:  1                      Mean   :21.15  
##  3rd Qu.:100   subj103:  1                      3rd Qu.:20.00  
##  Max.   :100   subj104:  1                      Max.   :63.00  
##                (Other):125                                     
##     gender              group    numeracy_total   reasoning_total
##  Length:131         Complex:65   Min.   : 0.000   Min.   : 4.00  
##  Class :character   Simple :66   1st Qu.: 8.000   1st Qu.: 8.00  
##  Mode  :character                Median :10.000   Median : 8.00  
##                                  Mean   : 8.779   Mean   : 8.45  
##                                  3rd Qu.:10.000   3rd Qu.: 9.00  
##                                  Max.   :11.000   Max.   :12.00  
##                                                                  
##  openminded_total thinking_total      stage     truth_estimate  
##  Min.   :19.0     Min.   :0.0000   stage1:131   Min.   :  0.00  
##  1st Qu.:33.5     1st Qu.:0.0000   stage2:  0   1st Qu.: 43.50  
##  Median :39.0     Median :0.0000   stage3:  0   Median : 61.00  
##  Mean   :38.2     Mean   :0.8092   stage4:  0   Mean   : 57.09  
##  3rd Qu.:43.0     3rd Qu.:1.0000   stage5:  0   3rd Qu.: 75.50  
##  Max.   :48.0     Max.   :3.0000   stage6:  0   Max.   :100.00  
##                                    stage7:  0

Alternatively, we can use base Rsummaryfunctionskimr` library:

data_exp1 %>% 
  group_by(subject) %>% 
  filter(row_number()==1) %>% 
  ungroup () %>% 
  dplyr::select (age, numeracy_total, reasoning_total, openminded_total, thinking_total) %>% 
  skimr::skim()
skim_type skim_variable n_missing complete_rate numeric.mean numeric.sd numeric.p0 numeric.p25 numeric.p50 numeric.p75 numeric.p100 numeric.hist
numeric age 0 1 21.1526718 6.515630 16 18.0 19 20 63 ▇▁▁▁▁
numeric numeracy_total 0 1 8.7786260 2.274576 0 8.0 10 10 11 ▁▁▁▂▇
numeric reasoning_total 0 1 8.4503817 1.683466 4 8.0 8 9 12 ▁▅▇▆▃
numeric openminded_total 0 1 38.1984733 6.153698 19 33.5 39 43 48 ▁▂▇▇▆
numeric thinking_total 0 1 0.8091603 1.038598 0 0.0 0 1 3 ▇▃▁▂▂

5.0.2 Exercise

For this exercise, we use a dataset of one of my own studies. In this study, we asked participants to guess the physical brightness of reasoning arguments and then we gave a cognitive ability test. (See the original study here). Open ghasemi_brightness_exp4.csv file and answer to the following questions:

  1. How many participants did we test in total?
  2. Find out how many male and female we tested.
  3. Calculate mean and sd for age and cognitive ability (cog_ability).
ghasemi_data <- read_csv(here("cleaned_data","ghasemi_brightness_exp4.csv"))

ghasemi_data %>% summarise(n = n_distinct(participant)) # number of participants:200
n
200
ghasemi_data %>% group_by (participant) %>% filter (row_number()==1) %>% group_by (gender) %>% summarise(n= n()) %>% ungroup() # 183 female, 17 male
gender n
Female 183
Male 17
ghasemi_data %>% dplyr::select (age, cog_ability) %>% skimr::skim() # mean and sd for age and cognitive ability
Data summary
Name Piped data
Number of rows 38400
Number of columns 2
_______________________
Column type frequency:
numeric 2
________________________
Group variables

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
age 0 1 22.20 6.78 17 19 20 22 52 ▇▁▁▁▁
cog_ability 0 1 39.55 9.46 11 34 40 46 61 ▁▃▇▆▂

6 Data Visualization

Before starting the ggplot, lets try a visualization using a function from the Base R the plot() function shows the association of each variable against the other one in a data handy for data with few number of variables to see if there are any patterns

exam_data<- read_csv(here::here("cleaned_data", "exam_data.csv"))

plot(x = exam_data$Anxiety, y = exam_data$Exam)

The code also works without writing x and y, however, writing them is strongly recommended

plot(exam_data$Anxiety, exam_data$Exam)

ggplot, the gg in ggplot stands for grammar of graphics. Grammar of graphics basically says any graphical representation of data, can be produced by a series of layers. You can think of a layer as a plastic transparency. Lets draw the same plot using ggplot. Always, mention the data we are going to work with.

ggplot(data = exam_data, aes(x = Exam, y = Anxiety))

  • aes: aes which stands for aesthetics is a relationship between a variable in your dataset and an aspect of the plot that is going to visually convey the information to the reader

  • Visual elements are known as geoms (short for ‘geometric objects’) in ggplot 2. When we define a layer, we have to tell R what geom we want displayed on that layer (do we want a bar, line dot, etc.?)

ggplot(data = exam_data, aes(x = Exam, y = Anxiety))+ geom_point()

So, lets try some of them here like shape and size. Be careful with the + sign, if you clink enter for the next part of the code, the + sign should not go to the next line

ggplot(data = exam_data, aes(x = Exam, y = Anxiety))+
  geom_point(size = 2, shape = 8)

The current plot is not very informative about the patterns for each gender.

ggplot(data = exam_data, aes(x = Exam, y = Anxiety, color = Gender))+
  geom_point(size = 2, shape = 10)

ggplot(data = exam_data, aes(x = Exam, y = Anxiety, color = Gender, shape = Gender))+
  geom_point(size = 2, shape = 10)

Question: why the above code doesn’t make any change?

ggplot(data = exam_data, aes(x = Exam, y = Anxiety, color = Gender, shape = Gender))+
  geom_point(size = 2)

Can assign the first layer to a variable to reduce the length of codes for next layers.

My_graph <- ggplot(data = exam_data, aes(x = Exam, y = Anxiety))

My_graph + geom_point()

lets add a line to the current graph

My_graph + geom_point() + geom_smooth()

Aesthetics can be set for all layers of the plot (i.e., defined in the plot as a whole) or can be set individually for each geom in a plot.

My_graph + geom_point(aes(color = Gender)) + geom_smooth()

My_graph + geom_point(aes(color = Gender)) + geom_smooth(aes(color = Gender))

The shaded area around the line is the 95% confidence interval around the line. We can switch this off by adding se = F (which is short for ‘standard error = False’)

My_graph + geom_point() + geom_smooth(se = F)

What if we want our line to be a direct line?

My_graph + geom_point() + geom_smooth(se = F, method = lm)

How to change the labels of x and y axes?

My_graph + geom_point() + geom_smooth(se = F, method = lm) +
  labs(x = "Exam scores %", y = "Anxiety scores")

Histograms are used to show distributions of variables while bar charts are used to compare variables. Histograms plot quantitative data with ranges of the data grouped into bins or intervals while bar charts plot categorical data.

#ggplot(data = exam_data, aes(x = Anxiety, y = Exam )) + geom_histogram()
# the code above gives an error as geom_histogram can only have x or y axis in its aes()

ggplot(data = exam_data, aes(x = Anxiety)) + geom_histogram()

ggplot(data = exam_data, aes(y = Anxiety)) + geom_histogram()

ggplot(data = exam_data, aes(x = Anxiety)) + geom_histogram(bins = 31)

ggplot(data = exam_data, aes(x = Anxiety)) + geom_histogram(bins = 31, fill = "green")

ggplot(data = exam_data, aes(x = Anxiety)) + geom_histogram(bins = 31, fill = "green", col = "red")

Let’s stop using the My_graph variable and write the whole code from the start again for a bar chart

ggplot(data = exam_data, aes(x = Sleep_quality))+
  geom_bar()

Because we want to plot a summary of the data (the mean) rather than the raw scores themselves, we have to use a stat.

ggplot(data = exam_data, aes(x = Sleep_quality, y = Exam, fill = Gender))+
  geom_bar(stat = "summary", fun = "mean")

ggplot(data = exam_data, aes(x = Sleep_quality, y = Exam, fill = Gender))+
  geom_bar(stat = "summary", fun = "mean", position = "dodge")

The other way to get the same plot that the code above gives, is using the stat_summary function that takes the following general form: stat_summary(function = x, geom = y)

ggplot(data = exam_data, aes(x = Sleep_quality, y = Exam, fill = Gender))+
  stat_summary(fun = mean, geom = "bar", position = "dodge")

How to combine multiple plots? How to combine multiple plots? We can use the patchwork package. A nice tutorial on using this package can be found here

p1 = My_graph + geom_point(aes(color = Gender)) + geom_smooth()

p2 = ggplot(data = exam_data, aes(x = Anxiety)) + geom_histogram(bins = 31)

p3 = ggplot(data = exam_data, aes(x = Sleep_quality, y = Exam, fill = Gender))+
  stat_summary(fun = mean, geom = "bar", position = "dodge")

p4 = My_graph + geom_point() + geom_smooth(se = F, method = lm) +
  labs(x = "Exam scores %", y = "Anxiety scores")

combined = p1 + p2+ p3 + p4 + plot_layout(nrow = 4, byrow = F)

combined

p1 | p2 / p3 / p4

p1 | p2 / (p3 / p4)

ggsave() function, which is a versatile exporting function that can export as PostScript (.eps/.ps), tex (pictex), pdf, jpeg, tiff, png, bmp, svg and wmf (in Windows only). In its basic form, the structure of the function is very simple: ggsave(filename)

ggsave(combined, filename = here("outputs", "combined.png"), dpi=300)

Now that we learned the basics of ggplot, let’s draw some plot for our experiment data. First, we need to create a dataset with aggregated truth estimate scores over group and stage. We will use this dataset for line and bar graphs.

aggregated_data_exp1 <- data_exp1 %>%
  group_by(stage, group) %>%
  mutate(truth_estimate = mean(truth_estimate)) %>%
  ungroup()

barplot_exp1 <- aggregated_data_exp1 %>%
  ggplot(aes(x=stage, y= truth_estimate, fill=group)) +
  geom_bar(stat = "identity", position= "dodge")+
  # stat_summary(fun= mean, geom = "bar", position = "dodge")+ # can be used instead of geom_bar() for long dataframes
  labs (x= '', y= "Truth Likelihhod Estimate") + 
  theme_bw() + 
  scale_fill_jama() 

barplot_exp1

barplot_facet_exp1 <- aggregated_data_exp1 %>%
  ggplot(aes(x=group, y= truth_estimate, fill=stage)) +
  geom_bar(stat = "identity", position= "dodge")+
  labs (x= '', y= "Truth Likelihhod Estimate") + 
  theme_bw() + 
  theme(legend.position = "none",
        axis.text=element_text(size=11),
        axis.title = element_text(size = 12)) +
  facet_wrap(~stage)+
  scale_fill_jco() 

barplot_facet_exp1

lineplot_exp1 <- aggregated_data_exp1 %>%
  ggplot(aes(x=factor(stage), y= truth_estimate, group= group, color= group)) +
  geom_line(aes(linetype= group)) +
  geom_point(size= 5)+
  labs (x= '', y= "Truth Likelihhod Estimate") + 
  theme_classic() +
  theme(legend.position = "bottom",
        axis.text=element_text(size=11),
        axis.title = element_text(size = 12)) +
  scale_color_nejm() 

lineplot_exp1

violinplot_exp1 <- data_exp1 %>%
  ggplot(aes(x=factor(stage), y= truth_estimate, fill= group)) +
  geom_violin()+
  labs (x= '', y= "Truth Likelihhod Estimate") + 
  theme_bw() + 
  theme(legend.position = "bottom",
        axis.text=element_text(size=11),
        axis.title = element_text(size = 12)) +
  scale_fill_d3() 

violinplot_exp1

boxplot_exp1 <- data_exp1 %>%
  ggplot(aes(x=factor(stage), y= truth_estimate, fill= group)) +
  geom_boxplot()+
  #geom_point(position = position_dodge(width=0.75), alpha= .5)+
  labs (x= '', y= "Truth Likelihhod Estimate") + 
  theme_bw() + 
  theme(legend.position = "bottom",
        axis.text=element_text(size=11),
        axis.title = element_text(size = 12)) +
  scale_fill_simpsons() 

boxplot_exp1

boxplot_facet_exp1 <- data_exp1 %>%
  ggplot(aes(x=factor(stage), y= truth_estimate, fill= group)) +
  geom_boxplot()+
  labs (x= '', y= "Truth Likelihhod Estimate") + 
  theme_bw() + 
  theme(legend.position = "bottom",
        axis.text=element_text(size=11),
        axis.title = element_text(size = 12),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
  facet_wrap(~group)+
  scale_color_simpsons() 

boxplot_facet_exp1

HLet’s combine our plots:

combined_plot_exp1 <- (barplot_facet_exp1+lineplot_exp1) / (violinplot_exp1+boxplot_exp1)
combined_plot_exp1

And here, we save our plots to the outputs folder.

ggsave(combined_plot_exp1, filename = here("outputs","combined_plot_exp1.png"), dpi=300)

7 Data Analysis

7.1 t-test

Now, we use the treatment data to run three different independent t-tests. Suppose we did an experiment to compare the effectiveness of CBT vs. Psychodynamic therapies in decreasing anxiety, and depression and also in improving life satisfaction:

# t.test (indep)
t.test(anxiety~treatment, data= treatment_data)
## 
##  Welch Two Sample t-test
## 
## data:  anxiety by treatment
## t = -0.85021, df = 124.18, p-value = 0.3968
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -12.11096   4.83264
## sample estimates:
##           mean in group CBT mean in group Psychodynamic 
##                    60.54545                    64.18462
t.test(depression~treatment, data= treatment_data)
## 
##  Welch Two Sample t-test
## 
## data:  depression by treatment
## t = -2.8725, df = 123.97, p-value = 0.004792
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -18.21965  -3.35424
## sample estimates:
##           mean in group CBT mean in group Psychodynamic 
##                    47.15152                    57.93846
t.test(life_satisfaction~treatment, data= treatment_data)
## 
##  Welch Two Sample t-test
## 
## data:  life_satisfaction by treatment
## t = -5.2688, df = 127.11, p-value = 0.0000005699
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -27.61850 -12.53721
## sample estimates:
##           mean in group CBT mean in group Psychodynamic 
##                    31.06061                    51.13846

In another experiment, suppose we have created a method to boost memory. Then, we recruit some participants, do a memory pre-test, implement the method, and do a memory post-test, Now, we want to see whether our method have improved participants’ memory:

# t.test (paired)
t.test(memory_score~time, data= memory_data, paired= T)
## 
##  Paired t-test
## 
## data:  memory_score by time
## t = 5.4761, df = 130, p-value = 0.0000002163
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##   7.333171 15.628661
## sample estimates:
## mean of the differences 
##                11.48092

Now that we learned about t-test, let’s perform this test on our dataset. Is there a difference between groups at the first stage? Ideally, we want participants’ ratings at the first stage be similar for both groups because we have not done any manipulations. Previous graphs showed us that ratings of simple and complex group at this stage are pretty close. Let’s test that using an independent t-test (because we have 2 independent groups):

# Is there a difference between groups at the first stage?
data_exp1 %>% 
  group_by(group) %>% 
  filter(stage=='stage1') %>% 
  ungroup () %>%
  t.test(truth_estimate~group, data = ., paired=FALSE)
## 
##  Welch Two Sample t-test
## 
## data:  truth_estimate by group
## t = -0.75145, df = 104.95, p-value = 0.4541
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -11.883716   5.351781
## sample estimates:
## mean in group Complex  mean in group Simple 
##              55.44615              58.71212

Now, we wonder if opposing arguments were effective at all, regardless of participants’ group. So, we would like to test if ratings at the final stage are lower than ratings at the stage 4? Since a pair of score at stage 4 and stage 7 is coming from a same person, we use paired t-test.

# Is there a difference between ratings of stage4 and stage7?
data_exp1 %>% 
  filter(stage=='stage4' | stage=='stage7') %>% 
  ungroup () %>%
  t.test(truth_estimate~stage, data = ., paired=TRUE)
## 
##  Paired t-test
## 
## data:  truth_estimate by stage
## t = 12.788, df = 130, p-value < 0.00000000000000022
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  32.64368 44.59296
## sample estimates:
## mean of the differences 
##                38.61832

7.1.1 Exercise

John et al. (2019) investigated the consequences of backing down (changing one’s mind in lights of evidence)and how other people view someone who change their mind. In their second experiments, they presented participants either with a person who changes their mind or a person who refuses to back down. Then, they asked participants to rate how intelligent and confident the person is (See the original study here). They reported that:

“Relative to the entrepreneur who did not back down, participants judged the entrepreneur who backed down as more intelligent (M_backed_down=5.13 out of 7, SD=1.09; M_did_not_back_down=3.97, SD=1.54; t(271.12)=−7.59, p < .001) but less confident (M_backed_down=4.50 out of 7, SD=1.36; M_did_not_back_down=5.65, SD=1.10; t(291.01)=8.08, p < .001).”.

Open the john_backdown_exp2.csv file and try to reproduce their results. Run two separate independent t-test, one with intelligent as the dependent variable and one with confident as the dependent variable. For both t-test, use back_down as the between-subject independent variable.

john_data <- read_csv(here("cleaned_data","john_backdown_exp2.csv"))


t.test(intelligent~back_down, data = john_data, paired=FALSE)
## 
##  Welch Two Sample t-test
## 
## data:  intelligent by back_down
## t = 7.5853, df = 271.12, p-value = 0.0000000000005319
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.8577107 1.4590076
## sample estimates:
##       mean in group backed_down mean in group did_not_back_down 
##                        5.129412                        3.971053
t.test(confident~back_down, data = john_data, paired=FALSE)
## 
##  Welch Two Sample t-test
## 
## data:  confident by back_down
## t = -8.0763, df = 291.01, p-value = 0.00000000000001787
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -1.4257768 -0.8670294
## sample estimates:
##       mean in group backed_down mean in group did_not_back_down 
##                        4.503268                        5.649671

7.2 Analysis of Variance (ANOVA)

Now, let’s answer our main question: Do participants in the simple group show higher ratings for supportive arguments (stage 2 to 4) and lower ratings for opposing arguments (stage 5 to 7), compared to participants in the complex group? If this is the case. we expect an interaction in the traditional Analysis of Variance (AONVA) test.

aov_m1 <- aov_car (truth_estimate ~ group*stage +
                     Error(subject/stage), data = data_exp1)
Effect df MSE F ges p.value
group 1, 129 949.04 0.01 <.0001 .94
stage 4.45, 574.05 515.69 59.48 *** .25 <.0001
group:stage 4.45, 574.05 515.69 13.34 *** .07 <.0001

As you can see, we found a significant main effect of stage and a significant group by stage interaction. We can use the emmeans package to do post-hoc tests.

# main effect of stage
emmeans(aov_m1, 'stage')
##  stage  emmean   SE  df lower.CL upper.CL
##  stage1   57.1 1.88 763     53.4     60.8
##  stage2   66.8 1.88 763     63.1     70.5
##  stage3   74.6 1.88 763     70.9     78.3
##  stage4   79.6 1.88 763     75.9     83.3
##  stage5   62.4 1.88 763     58.7     66.1
##  stage6   52.5 1.88 763     48.9     56.2
##  stage7   41.1 1.88 763     37.4     44.8
## 
## Results are averaged over the levels of: group 
## Warning: EMMs are biased unless design is perfectly balanced 
## Confidence level used: 0.95
pairs(emmeans(aov_m1, 'stage'), adjust= 'holm')
##  contrast        estimate   SE  df t.ratio p.value
##  stage1 - stage2    -9.74 2.42 774 -4.031  0.0004 
##  stage1 - stage3   -17.53 2.42 774 -7.256  <.0001 
##  stage1 - stage4   -22.50 2.42 774 -9.311  <.0001 
##  stage1 - stage5    -5.29 2.42 774 -2.187  0.1160 
##  stage1 - stage6     4.53 2.42 774  1.876  0.1220 
##  stage1 - stage7    15.98 2.42 774  6.613  <.0001 
##  stage2 - stage3    -7.79 2.42 774 -3.225  0.0066 
##  stage2 - stage4   -12.76 2.42 774 -5.280  <.0001 
##  stage2 - stage5     4.46 2.42 774  1.844  0.1220 
##  stage2 - stage6    14.28 2.42 774  5.908  <.0001 
##  stage2 - stage7    25.72 2.42 774 10.644  <.0001 
##  stage3 - stage4    -4.97 2.42 774 -2.055  0.1206 
##  stage3 - stage5    12.25 2.42 774  5.069  <.0001 
##  stage3 - stage6    22.07 2.42 774  9.132  <.0001 
##  stage3 - stage7    33.51 2.42 774 13.869  <.0001 
##  stage4 - stage5    17.22 2.42 774  7.124  <.0001 
##  stage4 - stage6    27.04 2.42 774 11.188  <.0001 
##  stage4 - stage7    38.48 2.42 774 15.924  <.0001 
##  stage5 - stage6     9.82 2.42 774  4.064  0.0004 
##  stage5 - stage7    21.27 2.42 774  8.800  <.0001 
##  stage6 - stage7    11.45 2.42 774  4.736  <.0001 
## 
## Results are averaged over the levels of: group 
## P value adjustment: holm method for 21 tests
# group by stage interaction
emmeans(aov_m1, "group", by= "stage")
## stage = stage1:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   55.4 2.67 766     50.2     60.7
##  Simple    58.7 2.65 761     53.5     63.9
## 
## stage = stage2:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   63.3 2.67 766     58.1     68.6
##  Simple    70.3 2.65 761     65.1     75.5
## 
## stage = stage3:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   70.0 2.67 766     64.7     75.2
##  Simple    79.3 2.65 761     74.1     84.5
## 
## stage = stage4:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   71.6 2.67 766     66.3     76.8
##  Simple    87.6 2.65 761     82.4     92.8
## 
## stage = stage5:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   64.2 2.67 766     58.9     69.4
##  Simple    60.5 2.65 761     55.3     65.8
## 
## stage = stage6:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   57.9 2.67 766     52.7     63.2
##  Simple    47.2 2.65 761     41.9     52.4
## 
## stage = stage7:
##  group   emmean   SE  df lower.CL upper.CL
##  Complex   51.1 2.67 766     45.9     56.4
##  Simple    31.1 2.65 761     25.9     36.3
## 
## Warning: EMMs are biased unless design is perfectly balanced 
## Confidence level used: 0.95
update(pairs(emmeans(aov_m1, "group", by= "stage")), by = NULL, adjust = "holm") 
##  contrast         stage  estimate   SE  df t.ratio p.value
##  Complex - Simple stage1    -3.27 3.76 763 -0.868  0.6673 
##  Complex - Simple stage2    -6.96 3.76 763 -1.851  0.1935 
##  Complex - Simple stage3    -9.29 3.76 763 -2.469  0.0550 
##  Complex - Simple stage4   -16.02 3.76 763 -4.259  0.0001 
##  Complex - Simple stage5     3.64 3.76 763  0.967  0.6673 
##  Complex - Simple stage6    10.79 3.76 763  2.868  0.0213 
##  Complex - Simple stage7    20.08 3.76 763  5.337  <.0001 
## 
## P value adjustment: holm method for 7 tests

You can use the afex_plot function from afex to create beautiful plots. Those plots interacts nicely with ggplot:

afex_plot(aov_m1, x = "stage", trace = "group", error='between',
          line_arg = list(size=1),
          point_arg = list(size=3.5),
          data_arg = list(size= 1, color= 'grey', width=.4),
          data_geom = geom_boxplot,
          mapping = c("linetype", "shape", "fill"),
          legend_title = "Group") +
  labs(y = "Truth Likelihhod Estimate", x = "") +
  theme_bw()+ # remove the grey background and grid
  theme(axis.text=element_text(size=13),
        axis.title = element_text(size = 13),
        legend.text=element_text(size=13),
        legend.title=element_text(size=13),
        legend.position='bottom',
        legend.key.size = unit(1, "cm"),
        legend.background = element_rect(colour = 'black', fill = 'white', linetype='solid'))+
  scale_color_simpsons() +
  scale_fill_simpsons()

If you are interested in this topic, check out this nice tutorial about using afex to run ANOVA, and also this interesting tutorial on the emmeans package.

7.2.1 Exercise

Rotello et al. (2018) investigated the association between the race (White vs. Black faces) and the gun-tool judgments. In their first experiments, they presented participants with 16 White male faces and 16 Black male faces, and following that 8 images of guns and 8 images of tools. They asked participants to judge if the object is a tool or a gun by pressing keyboard buttons. Then, they ran an ANOVA to see if participants’ gun responses are higher for any of the races. So, they included prime race (Black, White) and target identity (gun, tool) as independent variables and participants’ gun responses as dependent variable into their linear model (See the original study here). They found that:

“Participants made more gun responses to guns than to tools, F(1,45) = 53243, p < 0.0001, η2g = 0.998. However, the race of the prime face did not matter, F(1,45) = 0.287, p > 0.59, η2g = 0.001, nor was there an interaction of prime race with target object, F(1,45) = 0.022, p > 0.88, η2g = 0.000)”.

Open the rotello_shooter_exp1.csv file and try to reproduce their results. Run an ANOVA (type III) with resp as the dependent variable and target, prime, and their interaction as independent variables.

# load the general data file
rotello_data <- read_csv(here("cleaned_data","rotello_shooter_exp1.csv"))

# ANOVA
rotello_aov <- aov_car (resp ~ target*prime +
           Error(subject/target*prime), data = rotello_data)
Effect df MSE F ges p.value
target 1, 45 0.00 53242.99 *** >.99 <.0001
prime 1, 45 0.00 0.29 .001 .59
target:prime 1, 45 0.00 0.02 <.0001 .88

7.3 Correlation

Here, we want to check the correlation between variables on the narcissism_data. First, we need to remove subject column because it is not numeric:

narcissism_data_cor <- narcissism_data %>%
  select(-subject)
#-- Base R:
cor(narcissism_data_cor, method = "pearson",  use = "complete.obs")

#-- Psych library:
psych::pairs.panels(narcissism_data_cor, method = "pearson", hist.col = "#00AFBB", density = T, ellipses = F, stars = T)

#-- Correlation library:
# install.packages("devtools")
# devtools::install_github("easystats/correlation")
#library("correlation")
correlation::correlation(narcissism_data_cor) %>% summary()

#-- apaTables library:
narcissism_data_cor %>% 
  apaTables::apa.cor.table(filename="./outputs/CorMatrix.doc", show.conf.interval=T)
psychopathy self_esteem narcissism mental_health
psychopathy 1.00 0.15 0.40 -0.44
self_esteem 0.15 1.00 0.11 -0.29
narcissism 0.40 0.11 1.00 -0.26
mental_health -0.44 -0.29 -0.26 1.00
Parameter mental_health narcissism self_esteem
psychopathy -0.44 0.40 0.15
self_esteem -0.29 0.11
narcissism -0.26

Now that we learned about correlation test, let’s answer to another question of this study: does persuasion and dissuasion is related to open-mindedness, cognitive ability, reasoning abilities, and thinking style? To answer this question, we need to create two indexes (scores) one for persuasion and one for dissuasion. Then we can do a correlation test:

cor_data_exp1 <- data_exp1 %>% 
  pivot_wider(names_from = stage, values_from = truth_estimate) %>%
  group_by(subject) %>%
  mutate(persuasion_index= stage2+ stage3+ stage4 - stage1,
         dissuasion_index= (101-stage5) + (101-stage6) + (101-stage7) - (101-stage4)) %>%
  ungroup()%>%
  dplyr::select(persuasion_index,dissuasion_index,openminded_total,numeracy_total,thinking_total,reasoning_total)

#---------- Base R:
cor(cor_data_exp1, method = "pearson",  use = "complete.obs")

#---------- Psych library:
cor_data_exp1 %>% 
  psych::pairs.panels(method = "pearson", hist.col = "#00AFBB", density = T, ellipses = F, stars = T)

#---------- Correlation library:
correlation::correlation(cor_data_exp1) %>% summary()

#---------- apaTables library:
cor_data_exp1 %>% 
  apaTables::apa.cor.table(filename="./outputs/CorMatrix.doc", show.conf.interval=T)
persuasion_index dissuasion_index openminded_total numeracy_total thinking_total reasoning_total
persuasion_index 1.00 0.26 0.25 0.16 0.16 0.11
dissuasion_index 0.26 1.00 -0.03 -0.03 -0.09 0.15
openminded_total 0.25 -0.03 1.00 0.40 0.26 0.11
numeracy_total 0.16 -0.03 0.40 1.00 0.44 0.15
thinking_total 0.16 -0.09 0.26 0.44 1.00 0.29
reasoning_total 0.11 0.15 0.11 0.15 0.29 1.00
Parameter reasoning_total thinking_total numeracy_total openminded_total dissuasion_index
persuasion_index 0.11 0.16 0.16 0.25 0.26
dissuasion_index 0.15 -0.09 -0.03 -0.03
openminded_total 0.11 0.26 0.40
numeracy_total 0.15 0.44
thinking_total 0.29

7.3.1 Exercise

Pennycook et al. (2020) investigated the relationship between actively open-minded thinking style about evidence (AOT-E) and different political, scientific, and religious beliefs (see the original paper here). In their first experiment, they calculated the correlation of AOTE and scientific beliefs items (global warming, evolution, etc.) and they found the following results:

Open the pennycook_aote_exp1.csv file and try to reproduce their results by creating the same correlation matrix.

pennycook_data <- read_csv(here("cleaned_data","pennycook_aote_exp1.csv")) 


#---------- Base R:
cor(pennycook_data, method = "pearson",  use = "complete.obs")

#---------- Psych library:
pennycook_data %>% 
  psych::pairs.panels(method = "pearson", hist.col = "#00AFBB", density = T, ellipses = F, stars = T)

#---------- Correlation library:
correlation::correlation(pennycook_data) %>% summary()

#---------- apaTables library:
pennycook_data %>% 
  apaTables::apa.cor.table(filename="./outputs/CorMatrix.doc", show.conf.interval=T)
Parameter trust_scien gm_health tech_problems modern_medicine old_earth vaccines stem_cell big_bang evolution global_warming
aote 0.35 0.36 0.44 0.33 0.40 0.47 0.45 0.51 0.51 0.37
global_warming 0.42 0.06 0.14 0.18 0.33 0.26 0.31 0.33 0.38
evolution 0.48 0.33 0.28 0.36 0.47 0.39 0.54 0.78
big_bang 0.49 0.37 0.28 0.36 0.45 0.37 0.54
stem_cell 0.47 0.34 0.36 0.47 0.40 0.40
vaccines 0.43 0.52 0.49 0.53 0.38
old_earth 0.29 0.24 0.21 0.33
modern_medicine 0.43 0.42 0.47
tech_problems 0.33 0.39
gm_health 0.31

7.4 Linear Regression

Here, we do single and multiple linear regreassion on the narcissism_data:

m1 <- lm(mental_health~narcissism, data= narcissism_data)
term estimate std.error statistic p.value
(Intercept) 4.86 0.56 8.75 0
narcissism -0.04 0.01 -3.04 0
m2 <- lm(mental_health~narcissism+psychopathy, data= narcissism_data)
term estimate std.error statistic p.value
(Intercept) 5.43 0.53 10.27 0.00
narcissism -0.02 0.01 -1.09 0.28
psychopathy -0.19 0.04 -4.71 0.00

Now, let’s perform regression analyses on our own dataset. In the previous section, we found that open-mindedness (AOT-E) is correlated with persuasion. Now, one may ask if open-mindedness can predict persuasion after controlling for reasoning and controlling abilities? To answer that, we can run a multiple regression analysis:

exp1_reg=lm(persuasion_index ~ openminded_total+ numeracy_total+ thinking_total+ reasoning_total,
                  data=cor_data_exp1)
term estimate std.error statistic p.value
(Intercept) 78.57 33.08 2.38 0.02
openminded_total 1.62 0.72 2.23 0.03
numeracy_total 0.72 2.11 0.34 0.73
thinking_total 3.09 4.51 0.68 0.49
reasoning_total 1.77 2.52 0.70 0.48

7.4.1 Exercise

Trémolière and Djeriouat (2020) examined the role of cognitive reflection and belief in science in climate change skepticism. In their first study, they revealed that cognitive reflection and belief in science negetively predicted climate change skepticism even after controlling for demographic and cognitive ability variables (see the original paper here).

Open the tremoliere_data_exp1.csv file and try to reproduce their results by running a multiple linear regression. Enter age, gender, education, belief in science, literacy, numeracy (Numtotal), and cognitive reflection as predictors and enter climate change skepticism (climato) as the outcome variable.

Tremoliere_data <- read_csv(here("cleaned_data","tremoliere_data_exp1.csv"))

Tremoliere_reg=lm(Climato ~ Age+ Gender+ Education+ BeliefInSciencetotal+ Literacy+ Numtotal+ CognitiveReflection,
                    data=Tremoliere_data)
term estimate std.error statistic p.value
(Intercept) 57.57 5.19 11.09 0.00
Age 0.01 0.05 0.24 0.81
Gender -5.68 1.34 -4.23 0.00
Education 0.54 0.38 1.43 0.15
BeliefInSciencetotal -0.20 0.06 -3.62 0.00
Literacy -0.49 0.51 -0.96 0.34
Numtotal -1.52 0.83 -1.82 0.07
CognitiveReflection -18.58 4.26 -4.37 0.00
r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC deviance df.residual nobs
0.19 0.17 12.65 11.91 0 7 -1467.77 2953.54 2988.81 58235.89 364 372

8 Rmarkdown

To be completed…

9 References

  • Ghasemi, O., Handley, S., & Howarth, S. (2020). The Bright Homunculus in our Head: Individual Differences in Intuitive Sensitivity to Logical Validity.

  • John, L. K., Jeong, M., Gino, F., & Huang, L. (2019). The self-presentational consequences of upholding one’s stance in spite of the evidence. Organizational Behavior and Human Decision Processes, 154, 1-14.

  • Pennycook, G., Cheyne, J. A., Koehler, D. J., & Fugelsang, J. A. (2020). On the belief that beliefs should change according to evidence: Implications for conspiratorial, moral, paranormal, political, religious, and science beliefs. Judgment and Decision Making, 15(4), 476.

  • Rotello, C. M., Kelly, L. J., Heit, E., Vazire, S., & Vul, E. (2018). The Shape of ROC Curves in Shooter Tasks: Implications for Best Practices in Analysis. Collabra: Psychology, 4(1).

  • Trémolière, B., & Djeriouat, H. (2020). Don’t you see that its cold! Exploring the roles of cognitive reflection, climate science literacy, illusion of knowledge, and political orientation in climate change skepticism.

  • Wickham, H. (2014). Tidy data. Journal of Statistical Software, 59(10), 1-23.

LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFIiCmF1dGhvcjoKICAtIG5hbWU6ICJPbWlkIEdoYXNlbWkiCiAgICBhZmZpbGlhdGlvbjogTWFjcXVhcmllIFVuaXZlcnNpdHkKICAgIGVtYWlsOiBvbWlkcmV6YS5naGFzZW1pQGhkci5tcS5lZHUuYXUKICAtIG5hbWU6ICJNYWhkaSBNYXppZGkiCiAgICBhZmZpbGlhdGlvbjogVW5pdmVyc2l0eSBvZiBXZXN0ZXJuIEF1c3RyYWxpYQogICAgZW1haWw6IG1haGRpLm1hemlkaXNoYXJhZmFiYWRpQHJlc2VhcmNoLnV3YS5lZHUuYXUKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICBrZWVwX21kOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdGhlbWU6IGNlcnVsZWFuCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAjY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgZGZfcHJpbnQ6ICJrYWJsZSIKLS0tCgpUaGlzIGRvY3VtZW50IGlzIHRoZSBzdW1tYXJ5IG9mIHRoZSAqKkludHJvZHVjdGlvbiB0byBSKiogd29ya3Nob3AuIAoKQWxsIGNvcnJlc3BvbmRlbmNlIHJlbGF0ZWQgdG8gdGhpcyBkb2N1bWVudCBzaG91bGQgYmUgYWRkcmVzc2VkIHRvOiAKCjxjZW50ZXI+Ck9taWQgR2hhc2VtaSAoTWFjcXVhcmllIFVuaXZlcnNpdHksIFN5ZG5leSwgTlNXLCAyMTA5LCBBVVNUUkFMSUEpIAoKRW1haWw6IG9taWRyZXphLmdoYXNlbWlAaGRyLm1xLmVkdS5hdSAKPC9jZW50ZXI+CgoKCjxzdHlsZT4KCmJvZHl7IC8qIE5vcm1hbCAgKi8KICAgICAgZm9udC1zaXplOiAxOHB4OwogICAgICB0ZXh0LWFsaWduOiBqdXN0aWZ5OwogICAgICBsaW5lLWhlaWdodDogMS42OwogICAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKfQpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKfQpwcmUgeyAvKiBDb2RlIGJsb2NrIC0gZGV0ZXJtaW5lcyBjb2RlIHNwYWNpbmcgYmV0d2VlbiBsaW5lcyAqLwogICAgZm9udC1zaXplOiAxMnB4Owp9Cgo8L3N0eWxlPgoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249ImNlbnRlciIpCmBgYAoKCgpgYGB7ciBsaWJyYXJpZXMsIG1lc3NhZ2U9RkFMU0UsIGVjaG89Rn0KIyBsb2FkIGxpYnJhcmllcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoYWZleCkKbGlicmFyeShlbW1lYW5zKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNraW1yKQojIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikKIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImVhc3lzdGF0cy9jb3JyZWxhdGlvbiIpCmxpYnJhcnkoImNvcnJlbGF0aW9uIikKb3B0aW9ucyhzY2lwZW49OTk5KSAjIHR1cm4gb2ZmIHNjaWVudGlmaWMgbm90YXRpb25zCm9wdGlvbnMoY29udHJhc3RzID0gYygnY29udHIuc3VtJywnY29udHIucG9seScpKSAjIHNldCB0aGUgY29udHJhc3Qgc3VtIGdsb2JhbGx5IApvcHRpb25zKGtuaXRyLmthYmxlLk5BID0gJycpCmBgYAoKCiMgUmVzZWFyY2ggUXVlc3Rpb24KCgpUaGUgYWltIG9mIHRoZSBzdHVkeSBpcyB0byB0ZXN0IGlmIHNpbXBsZSBhcmd1bWVudHMgYXJlIG1vcmUgZWZmZWN0aXZlIGluIGJlbGllZiByZXZpc2lvbiB0aGFuIG1vcmUgY29tcGxleCBhcmd1bWVudHMuIFRvIHRoYXQgZW5kLCB3ZSBwcmVzZW50IHBhcnRpY2lwYW50cyB3aXRoIGFuIGltYWdpbmFyeSBzY2VuYXJpbyAodHdvIGFsaWVuIGNyZWF0dXJlcyBvbiBhIHBsYW5ldCkgYW5kIGEgdGhlb3J5IChvbmUgY3JlYXR1cmUgaXMgcHJlZGF0b3IgYW5kIHRoZSBvdGhlciBvbmUgaXMgcHJleSkgYW5kIHdlIGFzayB0aGVtIHRvIHJhdGUgdGhlIGxpa2VsaWhvb2QgdHJ1dGggb2YgdGhlIHRoZW9yeSBiYXNlZCBvbiBhIHNpbXBsZSBmYWN0IChXZSBhZGFwdGVkIHRoaXMgbWV0aG9kIGZyb20gR3JlZ2cgZXQgYWwuLDIwMTc7IHNlZSB0aGUgb3JpZ2luYWwgc3R1ZHkgW2hlcmVdKGh0dHBzOi8vam91cm5hbHMuc2FnZXB1Yi5jb20vZG9pLzEwLjEwODAvMTc0NzAyMTguMjAxNS4xMDk5MTYyKSkuIFRoZW4sIGluIGEgYmV0d2Vlbi1zdWJqZWN0IG1hbmlwdWxhdGlvbiwgcGFydGljaXBhbnRzIHdpbGwgYmUgcHJlc2VudGVkIHdpdGggZWl0aGVyIDYgc2ltcGxlIGFyZ3VtZW50cyAoTW9kdXMgUG9uZW5zIGNvbmRpdGlvbmFscykgb3IgNiBtb3JlIGNvbXBsZXggYXJndW1lbnRzIChNb2R1cyBUb2xsZW5zIGNvbmRpdGlvbmFscyksIGFuZCB0aGV5IHdpbGwgYmUgYXNrZWQgdG8gcmF0ZSB0aGUgbGlrZWxpaG9vZCB0cnV0aCBvZiB0aGUgaW5pdGlhbCB0aGVvcnkgb24gNyBzdGFnZXMuIAoKVGhlIGZpcnN0IHN0YWdlIGlzIHRoZSBiYXNlIHJhdGluZyBzdGFnZS4gVGhlIG5leHQgdGhyZWUgc3RhZ2VzIGluY2x1ZGUgc3VwcG9ydGl2ZSBhcmd1bWVudHMgb2YgdGhlIHRoZW9yeSBhbmQgdGhlIGxhc3QgdGhyZWUgYXJndW1lbnRzIGluY2x1ZGUgZGlzcHJvdmluZyBhcmd1bWVudHMgb2YgdGhlIHRoZW9yeS4gV2UgaHlwb3RoZXNpemVkIHRoYXQgdGhlIGdyb3VwIHdpdGggc2ltcGxlIGFyZ3VtZW50cyBzaG93cyBiZXR0ZXIgcGVyc3Vhc2lvbiAoYXMgaXQgcmVmbGVjdHMgaW4gaGlnaGVyIHJhdGluZ3MgZm9yIHRoZSBzdXBwb3J0aXZlIGFyZ3VtZW50cykgYW5kIGJldHRlciBkaXNzdWFzaW9uIChhcyBpdCByZWZsZWN0cyBpbiBsb3dlciByYXRpbmdzIGZvciB0aGUgb3Bwb3NpbmcgYXJndW1lbnRzKS4KCkluIHRoZSBsYXN0IHBhcnQgb2YgdGhlIHN0dWR5LCBwYXJ0aWNpcGFudHMgd2lsbCBiZSBhc2tlZCB0byBhbnN3ZXIgc2V2ZXJhbCBjb2duaXRpdmUgY2FwYWNpdHkvc3R5bGUgbWVhc3VyZXMgaW5jbHVkaW5nIHRoaW5raW5nIHN0eWxlIChDUlQpLCBvcGVuLW1pbmRlZG5lc3MgKEFPVC1FKSwgcmVhc29uaW5nIGFiaWxpdHkgKG1pbmR3YXJlKSwgYW5kIG51bWVyYWN5IHNjYWxlcy4gV2UgaHlwb3RoZXNpemVkIHRoYXQgY29nbml0aXZlIGFiaWxpdHksIGNvZ25pdGl2ZSBzdHlsZSwgYW5kIG9wZW4tbWluZGVkbmVzcyBhcmUgcG9zaXRpdmUgcHJlZGljdG9ycyBvZiBwZXJzdWFzaW9uIGFuZCBkaXNzdWFzaW9uLiBUaGVzZSBhc3NvY2lhdGlvbnMgc2hvdWxkIGJlIG1vcmUgcHJvbm91bmNlZCBmb3IgcGFydGljaXBhbnRzIGluIHRoZSBncm91cCB3aXRoIGNvbXBsZXggYXJndW1lbnRzIGJlY2F1c2UgdGhlIGFiaWxpdHkgYW5kIHdpbGxpbmduZXNzIHRvIGVuZ2FnZSBpbiBkZWxpYmVyYXRpdmUgdGhpbmtpbmcgbWF5IGZhdm9yIHBhcnRpY2lwYW50cyB0byBhc3Nlc3MgdGhlIHVuZGVybHlpbmcgbG9naWNhbCBzdHJ1Y3R1cmUgb2YgdGhvc2UgYXJndW1lbnRzLiBIb3dldmVyLCBmb3IgcGFydGljaXBhbnRzIGluIHRoZSBzaW1wbGUgZ3JvdXAsIHRoZSBsb2dpY2FsIHN0cnVjdHVyZSBvZiBhcmd1bWVudHMgaXMgbW9yZSBldmlkZW50LCBzbyBwYXJ0aWNpcGFudHMgd2l0aCBsb3dlciBhYmlsaXR5IGNhbiBzdGlsbCBhc3Nlc3MgdGhlIGxvZ2ljYWwgc3RhdHVzIG9mIHRob3NlIGFyZ3VtZW50cy4KIAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBlY2hvPUZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCdpbnB1dHMnLCdleHBfZGVzaWduLnBuZycpKQpgYGAKClRodXMsIG91ciBoeXBvdGhlc2VzIGZvciB0aGlzIGV4cGVyaW1lbnQgYXJlIGFzIGZvbGxvd3M6CgotIFBhcnRpY2lwYW50cyBpbiB0aGUgZ3JvdXAgd2l0aCBzaW1wbGUgYXJndW1lbnRzIGhhdmUgaGlnaGVyIHJhdGluZ3MgZm9yIHN1cHBvcnRpdmUgYXJndW1lbnRzIChUaGV5IGFyZSBtb3JlIGVhc2lseSBwZXJzdWFkZWQgdGhhbiB0aG9zZSBpbiB0aGUgZ3JvdXAgd2l0aCBjb21wbGV4IGFyZ3VtZW50cykuCgotIFBhcnRpY2lwYW50cyBpbiB0aGUgZ3JvdXAgd2l0aCBzaW1wbGUgYXJndW1lbnRzIGhhdmUgbG93ZXIgcmF0aW5ncyBmb3Igb3Bwb3NpbmcgYXJndW1lbnRzIChUaGV5IGFyZSBtb3JlIGVhc2lseSBkaXNzdWFkZWQgdGhhbiB0aG9zZSBpbiB0aGUgZ3JvdXAgd2l0aCBjb21wbGV4IGFyZ3VtZW50cykuCgotIFRoZXJlIGFyZSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbnMgYmV0d2VlbiB0aGlua2luZyBzdHlsZSAoQ1JUKSwgb3Blbi1taW5kZWRuZXNzIChBT1QtRSksIHJlYXNvbmluZyBhYmlsaXR5IChtaW5kd2FyZSksIGFuZCBudW1lcmFjeSBzY2FsZXMgd2l0aCBib3RoIHBlcnN1YXNpb24gYW5kIGRpc3N1YXNpb24gaW5kZXhlcyBpbiBlYWNoIGdyb3VwIGFuZCBpbiB0aGUgZW50aXJlIHNhbXBsZS4gVGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIG1lYXN1cmVzIHNob3VsZCBiZSBzdHJvbmdlciwgYWx0aG91Z2ggbm90IHNpZ25pZmljYW50bHksIGZvciBwYXJ0aWNpcGFudHMgaW4gdGhlIGdyb3VwIHdpdGggY29tcGxleCBhcmd1bWVudHMuCgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI1NTBweCIsIG91dC5oZWlnaHQ9IjQwMHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgnaW5wdXRzJywncHJlZGljdGlvbl9wbG90LnBuZycpKQpgYGAKCgojIEdldHRpbmcgUmVhZHkKCkZpcnN0LCB3ZSBuZWVkIHRvIGRlc2lnbiB0aGUgZXhwZXJpbWVudC4gRm9yIHRoaXMgZXhwZXJpbWVudCwgd2UgdXNlIG9ubGluZSBwbGF0Zm9ybXMgZm9yIGRhdGEgY29sbGVjdGlvbi4gVGhlcmUgYXJlIHNldmVyYWwgb3B0aW9ucyBzdWNoIGFzIEdvcmlsbGEsIEpTcHN5Y2gsIFF1YWx0cmljcywgcHN5Y2hvSlMgKHBhdmxvdmlhKSwgZXRjLiBTaW5jZSB3ZSBkbyBub3QgbmVlZCBhbnkgcmVhY3Rpb24gdGltZSBkYXRhLCB3ZSBzaW1wbHkgdXNlIFF1YWx0cmljcy4gRm9yIGFuIG92ZXJ2aWV3IG9mIGRpZmZlcmVudCBsYWItYmFzZWQgYW5kIG9ubGluZSBwbGF0Zm9ybXMsIHNlZSBbaGVyZV0oaHR0cHM6Ly9vbWlkZ2hhc2VtaTIxLmdpdGh1Yi5pby9odW1hbl9kYXRhL1NjcmlwdHMvYmVoYXZpb3JhbF9kYXRhLmh0bWwpLiAKCk5leHQsIHdlIG5lZWQgdG8gZGVjaWRlIG9uIHRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIChzYW1wbGUgc2l6ZSkuIEZvciB0aGlzIHN0dWR5LCB3ZSBkbyBub3Qgc3VlIHBvd2VyIGFuYWx5c2lzIHNpbmNlIHdlIGNhbm5vdCBhY2Nlc3MgbW9yZSB0aGFuIDEyMCBwYXJ0aWNpcGFudHMuIEhvd2V2ZXIsIGl0IGlzIGhpZ2hseSBzdWdnZXN0ZWQgY2FsY3VsYXRlIHNhbXBsZSBzaXplIHVzaW5nIHBvd2VyIGVzdGltYXRpb24uIFlvdSBjYW4gZmluZCBzb21lIG5pY2UgdHV0b3JpYWxzIG9uIGhvdyB0byBkbyB0aGF0IFtoZXJlXShodHRwczovL2p1bGlhbnF1YW5kdC5jb20vcG9zdC9wb3dlci1hbmFseXNpcy1ieS1kYXRhLXNpbXVsYXRpb24taW4tci1wYXJ0LWkvKSwgW2hlcmVdKGh0dHBzOi8vbmlja2NoLWsuZ2l0aHViLmlvL0Vjb25vbWV0cmljc1NsaWRlcy9XZWVrXzA4L1Bvd2VyX1NpbXVsYXRpb25zLmh0bWwpLCBhbmQgW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9wYXJhbXRlc3QvdmlnbmV0dGVzL1NpbXVsYXRpbmctUG93ZXIuaHRtbCkuCgpBZnRlciB3ZSBjcmVhdGVkIHRoZSBleHBlcmltZW50IGFuZCBkZWNpZGVkIG9uIHRoZSBzYW1wbGUgc2l6ZSwgdGhlIG5leHQgc3RlcCBpcyB0byBwcmVyZXNpZ3RlciB0aGUgc3R1ZHkuIEhvd2V2ZXIsIGl0IHdvdWxkIGJlIGJldHRlciB0byBkbyBhIHBpbG90IHdpdGggNCBvciA1IHBhcnRpY2lwYW50cywgY2xlYW4gYWxsIHRoZSBkYXRhLCBkbyB0aGUgZGVzaXJlZCBhbmFseXNpcywgYW5kIHRoZW4gcHJlLXJlZ2lzdGVyIHRoZSBhbmFseXNpcyBhbmQgdGhvc2UgY29kZXMuIFlvdSBjYW4gZmluZCB0aGUgcHJlcmVnaXN0cmF0aW9uIGZvcm0gZm9yIHRoZSBjdXJyZW50IHN0dWR5IFtoZXJlXShodHRwczovL29zZi5pby83OXI2ZSkuCgpGaW5hbGx5LCB3ZSBuZWVkIHRvIHJlc3RydWN0dXJlIG91ciBwcm9qZWN0IGluIGEgdGlkeSBmb2xkZXIgd2l0aCBkaWZmZXJlbnQgc3ViLWZvbGRlcnMuIEhhdmluZyBhIGNsZWFuIGFuZCB0aWR5IGZvbGRlciBzdHJ1Y3R1cmUgY2FuIHNhdmUgdXMhIFRoZXJlIGFyZSBkaWZmZXJlbnQgZm9ybWF0cyBvZiBmb2xkZXIgc3RydWN0dXJlIChmb3IgZXhhbXBsZSwgc2VlIFtoZXJlXShodHRwOi8vbmlrb2xhLm1lL2ZvbGRlcl9zdHJ1Y3R1cmUuaHRtbCkgYW5kIFtoZXJlXShodHRwczovL3NsaWRlcy5jb20vZGpuYXZhcnJvL3dvcmtmbG93KSksIGJ1dCBmb3Igbm93LCB3ZSB1c2UgdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmU6CgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjcwMHB4Iiwgb3V0LmhlaWdodD0iMjAwcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCdpbnB1dHMnLCdmb2xkZXJfc3RydWN0dXJlLnBuZycpKQpgYGAKCgojIEludHJvZHVjdGlvbiB0byBSCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIGV2YWw9Rn0KIyBsb2FkIGxpYnJhcmllcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoYWZleCkKbGlicmFyeShlbW1lYW5zKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNraW1yKQojIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikKIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImVhc3lzdGF0cy9jb3JyZWxhdGlvbiIpCmxpYnJhcnkoImNvcnJlbGF0aW9uIikKb3B0aW9ucyhzY2lwZW49OTk5KSAjIHR1cm4gb2ZmIHNjaWVudGlmaWMgbm90YXRpb25zCm9wdGlvbnMoY29udHJhc3RzID0gYygnY29udHIuc3VtJywnY29udHIucG9seScpKSAjIHNldCB0aGUgY29udHJhc3Qgc3VtIGdsb2JhbGx5IApvcHRpb25zKGtuaXRyLmthYmxlLk5BID0gJycpCmBgYAoKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNzAwcHgiLCBvdXQuaGVpZ2h0PSI3MDBweCIsIGZpZy5jYXA9ICJBcnR3b3JrIGJ5IEFsbGlzb24gSG9yc3Q6IGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3Qvc3RhdHMtaWxsdXN0cmF0aW9ucyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ3JfZmlyc3RfdGhlbi5wbmcnKSkKYGBgCgoKUiBjYW4gYmUgdXNlZCBhcyBhIGNhbGN1bGF0b3IuIEZvciBtYXRoZW1hdGljYWwgcHVycG9zZXMsIGJlIGNhcmVmdWwgb2YgdGhlIG9yZGVyIGluIHdoaWNoIFIgZXhlY3V0ZXMgdGhlIGNvbW1hbmRzLgoKYGBge3J9CjEwICsgMTAKCjQgXiAyCgooMjUwIC8gNTAwKSAqIDEwMApgYGAKClIgaXMgYSBiaXQgZmxleGlibGUgd2l0aCBzcGFjaW5nIChidXQgbm8gc3BhY2luZyBpbiB0aGUgbmFtZSBvZiB2YXJpYWJsZXMgYW5kIHdvcmRzKQoKYGBge3J9CjEwKzEwCgoxMCAgICAgICAgICAgICAgICAgKyAgICAgICAgICAgMTAKYGBgCgpSIGNhbiBzb21ldGltZXMgdGVsbCB0aGF0IHlvdSdyZSBub3QgZmluaXNoZWQgeWV0CgpgYGB7ciBldmFsPUZ9CjEwICsKYGBgCgpIb3cgdG8gY3JlYXRlIGEgKnZhcmlhYmxlKj8gVmFyaWFibGUgYXNzaWdubWVudCB1c2luZyBgPC1gIGFuZCBgPWAuIE5vdGUgdGhhdCBSIGlzIGNhc2Ugc2Vuc2l0aXZlIGZvciBldmVyeXRoaW5nCgpgYGB7cn0KcGF5IDwtIDI1MAoKbW9udGggPSAxMgoKcGF5ICogbW9udGgKCnNhbGFyeSA8LSBwYXkgKiBtb250aApgYGAKCgpGZXcgcG9pbnRzIGluIG5hbWluZyB2YXJpYWJsZXMgYW5kIHZlY3RvcnM6IHVzZSBzaG9ydCwgaW5mb3JtYXRpdmUgd29yZHMsIGtlZXAgc2FtZSBtZXRob2QgKGUuZy4sIG5vdCB1c2luZyBjYXBpdGFsIHdvcmRzLCB1c2Ugb25seSBfIG9yIC4gKS4KCiMjIEZ1bmN0aW9uIApGdW5jdGlvbiBpcyBhIHNldCBvZiBzdGF0ZW1lbnRzIGNvbWJpbmVkIHRvZ2V0aGVyIHRvIHBlcmZvcm0gYSBzcGVjaWZpYyB0YXNrLiBXaGVuIHdlIHVzZSBhIGJsb2NrIG9mIGNvZGUgcmVwZWF0ZWRseSwgd2UgY2FuIGNvbnZlcnQgaXQgdG8gYSBmdW5jdGlvbi4gVG8gd3JpdGUgYSBmdW5jdGlvbiwgZmlyc3QsIHlvdSBuZWVkIHRvICpkZWZpbmUqIGl0OgoKYGBge3J9Cm15X211bHRpcGxpZXIgPC0gZnVuY3Rpb24oYSxiKXsKICByZXN1bHQgPSBhICogYgogIHJldHVybiAocmVzdWx0KQp9CmBgYAoKVGhpcyBjb2RlIGRvIG5vdGhpbmcuIFRvIGdldCBhIHJlc3VsdCwgeW91IG5lZWQgdG8gKmNhbGwqIGl0OgoKYGBge3J9Cm15X211bHRpcGxpZXIgKGE9MiwgYj00KQojIG9yOiBteV9tdWx0aXBsaWVyICgyLCA0KQpgYGAKCldlIGNhbiBzZXQgYSBkZWZhdWx0IHZhbHVlIGZvciBvdXIgYXJndW1lbnRzOgoKYGBge3J9Cm15X211bHRpcGxpZXIyIDwtIGZ1bmN0aW9uKGEsYj00KXsKICByZXN1bHQgPSBhICogYgogIHJldHVybiAocmVzdWx0KQp9CgpteV9tdWx0aXBsaWVyMiAoYT0yKQojIG9yOiBteV9tdWx0aXBsaWVyICgyKQojIG9yOiBteV9tdWx0aXBsaWVyICgyLCA2KQpgYGAKCkZvcnR1bmF0ZWx5LCB5b3UgZG8gbm90IG5lZWQgdG8gd3JpdGUgZXZlcnl0aGluZyBmcm9tIHNjcmF0Y2guIFIgaGFzIGxvdHMgb2YgYnVpbHQtaW4gZnVuY3Rpb25zIHRoYXQgeW91IGNhbiB1c2U6CmBgYHtyfQpyb3VuZCg1NC42Nzg3KQpyb3VuZCg1NC41Nzg3LCBkaWdpdHMgPSAyKQpgYGAKClVzZSBgP2AgYmVmb3JlIHRoZSBmdW5jdGlvbiBuYW1lIHRvIGdldCBzb21lIGhlbHAuIEZvciBleGFtcGxlLCBgP3JvdW5kYC4gWW91IHdpbGwgc2VlIG1hbnkgZnVuY3Rpb25zIGluIHRoZSByZXN0IG9mIHRoZSB3b3Jrc2hvcC4KCiMjIEJhc2ljIERhdGEgVHlwZXMgaW4gUjoKCmZ1bmN0aW9uIGBjbGFzcygpYCBpcyB1c2VkIHRvIHNob3cgd2hhdCBpcyB0aGUgdHlwZSBvZiBhIHZhcmlhYmxlLgoKCjEuICpMb2dpY2FsKjogYFRSVUVgLCBgRkFMU0VgIGNhbiBiZSBhYmJyZXZpYXRlZCBhcyBgVGAsIGBGYC4gIFRoZXkgaGFzIHRvIGJlIGNhcGl0YWwsICd0cnVlJyBpcyBub3QgYSBsb2dpY2FsIGRhdGE6CmBgYHtyfQpjbGFzcyhUUlVFKQpjbGFzcyhGKQpgYGAKCjIuICpOdW1lcmljKjogYWxsIG51bWJlcnMgZS5nLiA1LCAgMTAuNSwgIDExLDM3OyAgYSBzcGVjaWFsIHR5cGUgb2YgbnVtZXJpYyBpcyAiaW50ZWdlciIgd2hpY2ggaXMgbnVtYmVycyB3aXRob3V0IGRlY2ltYWwuIEludGVnZXJzIGFyZSBhbHdheXMgbnVtZXJpYywgYnV0IG51bWVyaWMgaXMgbm90IGFsd2F5cyBpbnRlZ2VyOgpgYGB7cn0KY2xhc3MoMikKY2xhc3MoMTMuNDYpCmBgYAoKMy4gKkNoYXJhY3Rlcio6IHRleHQgZm9yIGV4YW1wbGUsICJJIGxvdmUgUiIgb3IgIjQiIG9yICI0LjUiOgpgYGB7cn0KY2xhc3MoImhhIGhhIGhhIGhhIikKY2xhc3MoIjU2LjYiKQpjbGFzcygiVFJVRSIpCmBgYAoKQ2FuIHdlIGNoYW5nZSB0aGUgdHlwZSBvZiBkYXRhIGluIGEgdmFyaWFibGU/IFllcywgeW91IG5lZWQgdG8gdXNlIHRoZSBmdW5jdGlvbiBgYXMuLS0tKClgCgpgYGB7cn0KYXMubnVtZXJpYyhUUlVFKQphcy5jaGFyYWN0ZXIoNCkKYXMubnVtZXJpYygiNC41IikKYXMubnVtZXJpYygiSGVsbG8iKQpgYGAKCgojIyBEYXRhIFN0cnVjdHVyZXMgaW4gUgoKCioqVmVjdG9yKio6IHdoZW4gdGhlcmUgYXJlIG1vcmUgdGhhbiBvbmUgbnVtYmVyIG9yIGxldHRlciBzdG9yZWQuIFVzZSB0aGUgY29tYmluZSBmdW5jdGlvbiBjKCkgZm9yIHRoYXQuCgpgYGB7cn0Kc2FsZSA8LSBjKDEsIDIsIDMsNCwgNSwgNiwgNywgOCwgOSwgMTApICMgYWxzbyBzYWxlIDwtIGMoMToxMCkKCnNhbGUgPC0gYygxOjEwKQoKc2FsZSAqIHNhbGUKYGBgCgoqU3Vic2V0dGluZyBhIHZlY3Rvcio6CgpgYGB7cn0KZGF5cyA8LSBjKCJTYXR1cmRheSIsICJTdW5kYXkiLCAiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpCgpkYXlzWzJdCmRheXNbLTJdCgpkYXlzW2MoMiwgMywgNCldCmBgYAoKCiMjIyBFeGVyY2lzZQoKQ3JlYXRlIGEgdmVjdG9yIG5hbWVkIGBteV92ZWN0b3JgIHdpdGggbnVtYmVycyBmcm9tIDAgdG8gMTAwMCBpbiBpdDoKCmBgYHtyfQpteV92ZWN0b3IgPC0gKDA6MTAwMCkKCm1lYW4obXlfdmVjdG9yKQptZWRpYW4obXlfdmVjdG9yKQptaW4obXlfdmVjdG9yKQpyYW5nZShteV92ZWN0b3IpCmNsYXNzKG15X3ZlY3RvcikKc3VtKG15X3ZlY3RvcikKc2QobXlfdmVjdG9yKQpgYGAKCioqTGlzdCoqOiBhbGxvd3MgeW91IHRvIGdhdGhlciBhIHZhcmlldHkgb2Ygb2JqZWN0cyB1bmRlciBvbmUgbmFtZSAodGhhdCBpcywgdGhlIG5hbWUgb2YgdGhlIGxpc3QpIGluIGFuIG9yZGVyZWQgd2F5LiBUaGVzZSBvYmplY3RzIGNhbiBiZSBtYXRyaWNlcywgdmVjdG9ycywgZGF0YSBmcmFtZXMsIGV2ZW4gb3RoZXIgbGlzdC4KCmBgYHtyfQpteV9saXN0ID0gbGlzdChzYWxlLCAxLCAzLCA0OjcsICJIRUxMTyIsICJoZWxsbyIsIEZBTFNFKQpteV9saXN0CmBgYAoKKipGYWN0b3IqKjogRmFjdG9ycyBzdG9yZSB0aGUgdmVjdG9yIGFsb25nIHdpdGggdGhlIGRpc3RpbmN0IHZhbHVlcyBvZiB0aGUgZWxlbWVudHMgaW4gdGhlIHZlY3RvciBhcyBsYWJlbHMuIFRoZSBsYWJlbHMgYXJlIGFsd2F5cyBjaGFyYWN0ZXIgaXJyZXNwZWN0aXZlIG9mIHdoZXRoZXIgaXQgaXMgbnVtZXJpYyBvciBjaGFyYWN0ZXIuIEZvciBleGFtcGxlLCB2YXJpYWJsZSBnZW5kZXIgd2l0aCAibWFsZSIgYW5kICJmZW1hbGUiIGVudHJpZXM6CgpgYGB7cn0KZ2VuZGVyIDwtIGMoIm1hbGUiLCAibWFsZSIsICJtYWxlIiwgIiBmZW1hbGUiLCAiZmVtYWxlIiwgImZlbWFsZSIpCmdlbmRlciA8LSBmYWN0b3IoZ2VuZGVyKQpgYGAKClIgbm93IHRyZWF0cyBnZW5kZXIgYXMgYSBub21pbmFsIChjYXRlZ29yaWNhbCkgdmFyaWFibGU6IDE9ZmVtYWxlLCAyPW1hbGUgaW50ZXJuYWxseSAoYWxwaGFiZXRpY2FsbHkpLgpgYGB7cn0Kc3VtbWFyeShnZW5kZXIpCmBgYAoKKlF1ZXN0aW9uKjogd2h5IHdoZW4gd2UgcmFuIHRoZSBhYm92ZSBmdW5jdGlvbiBpLmUuIHN1bW1hcnkoKSwgaXQgc2hvd2VkIHRocmVlIGFuZCBub3QgdHdvIGxldmVscyBvZiB0aGUgZGF0YT8gKkhpbnQqOiBydW4gJ2dlbmRlcicuCgpgYGB7cn0KZ2VuZGVyCmBgYAoKU28sIGJlIGNhcmVmdWwgb2Ygc3BhY2VzIQoKIyMjIEV4ZXJjaXNlCkNyZWF0ZSBhIGdlbmRlciBmYWN0b3Igd2l0aCAzMCBtYWxlIGFuZCA0MCBmZW1hbGVzICgqSGludCo6IHVzZSB0aGUgYHJlcCgpYCBmdW5jdGlvbik6CmBgYHtyfQpnZW5kZXIgPC0gYyhyZXAoIm1hbGUiLDMwKSwgcmVwKCJmZW1hbGUiLCA0MCkpCmdlbmRlciA8LSBmYWN0b3IoZ2VuZGVyKQpnZW5kZXIKYGBgCgpUaGVyZSBhcmUgdHdvIHR5cGVzIG9mIGNhdGVnb3JpY2FsIHZhcmlhYmxlczogbm9taW5hbCBhbmQgb3JkaW5hbC4gSG93IHRvIGNyZWF0ZSBvcmRlcmVkIGZhY3RvcnMgKHdoZW4gdGhlIHZhcmlhYmxlIGlzIG5vbWluYWwgYW5kIHZhbHVlcyBjYW4gYmUgb3JkZXJlZCk/IFdlIHNob3VsZCBhZGQgdHdvIGFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIHRoZSBgZmFjdG9yKClgIGZ1bmN0aW9uOiBgb3JkZXJlZCA9IFRSVUVgLCBhbmQgYGxldmVscyA9IGMoImxldmVsMSIsICJsZXZlbDIiKWAuIEZvciBleGFtcGxlLCB3ZSBoYXZlIGEgdmVjdG9yIHRoYXQgc2hvd3MgcGFydGljaXBhbnRzJyBlZHVjYXRpb24gbGV2ZWwuCgpgYGB7cn0KZWR1PC1jKDMsMiwzLDQsMSwyLDIsMyw0KQoKZWR1Y2F0aW9uPC1mYWN0b3IoZWR1LCBvcmRlcmVkID0gVFJVRSkKbGV2ZWxzKGVkdWNhdGlvbikgPC0gYygiUHJpbWFyeSBzY2hvb2wiLCJoaWdoIHNjaG9vbCIsIkNvbGxlZ2UiLCJVbmkgZ3JhZHVhdGVkIikKZWR1Y2F0aW9uCmBgYAoKIyMjIEV4ZXJjaXNlCldlIGhhdmUgYSBmYWN0b3Igd2l0aCBgcGF0aWVudGAgYW5kIGBjb250cm9sYCB2YWx1ZXMuIEhlcmUsIHRoZSBmaXJzdCBsZXZlbCBpcyBjb250cm9sIGFuZCB0aGUgc2Vjb25kIGxldmVsIGlzIHBhdGllbnQuIENoYW5nZSB0aGUgb3JkZXIgb2YgbGV2ZWxzLCBzbyBwYXRpZW50IHdvdWxkIGJlIHRoZSBmaXJzdCBsZXZlbDoKCmBgYHtyfQpoZWFsdGhfc3RhdHVzIDwtIGZhY3RvcihjKHJlcCgncGF0aWVudCcsNSkscmVwKCdjb250cm9sJyw1KSkpCmhlYWx0aF9zdGF0dXMKCmhlYWx0aF9zdGF0dXNfcmVvcmRlcmVkIDwtIGZhY3RvcihoZWFsdGhfc3RhdHVzLCBsZXZlbHMgPSBjKCdwYXRpZW50JywnY29udHJvbCcpKQpoZWFsdGhfc3RhdHVzX3Jlb3JkZXJlZApgYGAKCkZpbmFsbHksIGNhbiB5b3UgcmVsYWJlbCBib3RoIGxldmVscyB0byB1cHBlcmNhc2UgY2hhcmFjdGVycz8gKCpIaW50KjogY2hlY2sgYD9mYWN0b3JgKQoKYGBge3J9CmhlYWx0aF9zdGF0dXNfcmVsYWJlbGVkIDwtIGZhY3RvcihoZWFsdGhfc3RhdHVzLCBsZXZlbHMgPSBjKCdwYXRpZW50JywnY29udHJvbCcpLCBsYWJlbHMgPSBjKCdQYXRpZW50JywnQ29udHJvbCcpKQpoZWFsdGhfc3RhdHVzX3JlbGFiZWxlZApgYGAKCgoqKk1hdHJpY2VzKio6IEFsbCBjb2x1bW5zIGluIGEgbWF0cml4IG11c3QgaGF2ZSB0aGUgc2FtZSBtb2RlKG51bWVyaWMsIGNoYXJhY3RlciwgZXRjLikgYW5kIHRoZSBzYW1lIGxlbmd0aC4gSXQgY2FuIGJlIGNyZWF0ZWQgdXNpbmcgYSB2ZWN0b3IgaW5wdXQgdG8gdGhlIG1hdHJpeCBmdW5jdGlvbi4KCmBgYHtyfQpteV9tYXRyaXggPSBtYXRyaXgoYygxLDIsMyw0LDUsNiw3LDgsOSksIG5yb3cgPSAzLCBuY29sID0gMykKCm15X21hdHJpeApgYGAKCioqRGF0YSBmcmFtZXMqKjogKHR3by1kaW1lbnNpb25hbCBvYmplY3RzKSBjYW4gaG9sZCBudW1lcmljLCBjaGFyYWN0ZXIgb3IgbG9naWNhbCB2YWx1ZXMuIFdpdGhpbiBhIGNvbHVtbiBhbGwgZWxlbWVudHMgaGF2ZSB0aGUgc2FtZSBkYXRhIHR5cGUsIGJ1dCBkaWZmZXJlbnQgY29sdW1ucyBjYW4gYmUgb2YgZGlmZmVyZW50IGRhdGEgdHlwZS4gTGV0J3MgY3JlYXRlIGEgZGF0YWZyYW1lOgoKYGBge3J9CmlkIDwtIDE6MjAwCmdyb3VwIDwtIGMocmVwKCJQc3ljaG90aGVyYXB5IiwgMTAwKSwgcmVwKCJNZWRpY2F0aW9uIiwgMTAwKSkKcmVzcG9uc2UgPC0gYyhybm9ybSgxMDAsIG1lYW4gPSAzMCwgc2QgPSA1KSwKICAgICAgICAgICAgIHJub3JtKDEwMCwgbWVhbiA9IDI1LCBzZCA9IDUpKQoKbXlfZGF0YWZyYW1lIDwtZGF0YS5mcmFtZShQYXRpZW50ID0gaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVHJlYXRtZW50ID0gZ3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgUmVzcG9uc2UgPSByZXNwb25zZSkKYGBgCgpXZSBhbHNvIGNvdWxkIGhhdmUgZG9uZSB0aGUgYmVsb3cKCmBgYHtyfQpteV9kYXRhZnJhbWUgPC1kYXRhLmZyYW1lKFBhdGllbnQgPSBjKDE6MjAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBUcmVhdG1lbnQgPSBjKHJlcCgiUHN5Y2hvdGhlcmFweSIsIDEwMCksIHJlcCgiTWVkaWNhdGlvbiIsIDEwMCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIFJlc3BvbnNlID0gYyhybm9ybSgxMDAsIG1lYW4gPSAzMCwgc2QgPSA1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm5vcm0oMTAwLCBtZWFuID0gMjUsIHNkID0gNSkpKQpgYGAKCkluIGxhcmdlIGRhdGEgc2V0cywgdGhlIGZ1bmN0aW9uIGhlYWQoKSBlbmFibGVzIHlvdSB0byBzaG93IHRoZSBmaXJzdCBvYnNlcnZhdGlvbnMgb2YgYSBkYXRhIGZyYW1lcy4gU2ltaWxhcmx5LCB0aGUgZnVuY3Rpb24gdGFpbCgpIHByaW50cyBvdXQgdGhlIGxhc3Qgb2JzZXJ2YXRpb25zIGluIHlvdXIgZGF0YSBzZXQuCgpgYGB7ciBldmFsPUZ9CmhlYWQobXlfZGF0YWZyYW1lKSAKdGFpbChteV9kYXRhZnJhbWUpCmBgYAoKYGBge3IgZWNobz1GfQpoZWFkKG15X2RhdGFmcmFtZSkgJT4lCiAga25pdHI6OmthYmxlKCkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IFQpCnRhaWwobXlfZGF0YWZyYW1lKSU+JQogIGtuaXRyOjprYWJsZSgpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiwgImNvbmRlbnNlZCIpLCBmaXhlZF90aGVhZCA9IFQsIGZ1bGxfd2lkdGggPSBUKQpgYGAKClNpbWlsYXIgdG8gdmVjdG9ycyBhbmQgbWF0cmljZXMsIGJyYWNrZXRzIFtdIGFyZSB1c2VkIHRvIHNlbGVjdHMgZGF0YSBmcm9tIHJvd3MgYW5kIGNvbHVtbnMgaW4gZGF0YS5mcmFtZXM6CgpgYGB7cn0KbXlfZGF0YWZyYW1lWzM1LCAzXQpgYGAKCiMjIyBFeGVyY2lzZQoKSG93IGNhbiB3ZSBnZXQgYWxsIGNvbHVtbnMsIGJ1dCBvbmx5IGZvciB0aGUgZmlyc3QgMTAgcGFydGljaXBhbnRzPwoKYGBge3IgZXZhbD1GfQpteV9kYXRhZnJhbWVbMToxMCwgXQpgYGAKCmBgYHtyIGVjaG89Rn0Ka25pdHI6OmthYmxlKG15X2RhdGFmcmFtZVsxOjEwLCBdKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgZml4ZWRfdGhlYWQgPSBULCBmdWxsX3dpZHRoID0gVCkKCmBgYApIb3cgdG8gZ2V0IG9ubHkgdGhlIFJlc3BvbnNlIGNvbHVtbiBmb3IgYWxsIHBhcnRpY2lwYW50cz8KCmBgYHtyfQpteV9kYXRhZnJhbWVbICwgM10KYGBgCgpBbm90aGVyIGVhc2llciB3YXkgZm9yIHNlbGVjdGluZyBwYXJ0aWN1bGFyIGl0ZW1zIGlzIHVzaW5nIHRoZWlyIG5hbWVzIHRoYXQgaXMgbW9yZSBoZWxwZnVsIHRoYW4gbnVtYmVyIG9mIHRoZSByb3dzIGluIGxhcmdlIGRhdGEgc2V0czoKYGBge3IgZXZhbD1GfQpteV9kYXRhZnJhbWVbICwgIlJlc3BvbnNlIl0KIyBPUjoKbXlfZGF0YWZyYW1lJFJlc3BvbnNlCgpgYGAKCgojIERhdGEgQ2xlYW5pbmcKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNzAwcHgiLCBvdXQuaGVpZ2h0PSIzNTBweCIsIGZpZy5jYXA9ICJBcnR3b3JrIGJ5IEFsbGlzb24gSG9yc3Q6IGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3Qvc3RhdHMtaWxsdXN0cmF0aW9ucyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ2Vudmlyb25tZW50YWwtZGF0YS1zY2llbmNlLXI0ZHMtZ2VuZXJhbC5wbmcnKSkKYGBgCgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI3MDBweCIsIG91dC5oZWlnaHQ9IjM1MHB4IiwgZmlnLmNhcD0gIkFydHdvcmsgYnkgQWxsaXNvbiBIb3JzdDogaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9zdGF0cy1pbGx1c3RyYXRpb25zIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgnaW5wdXRzJywnY3JhY2tlZF9zZXR3ZC5wbmcnKSkKYGBgCgpOb3csIHN1cHBvc2Ugd2UgdGVzdGVkIDE0MSBzdHVkZW50cy4gRmlyc3QsIGxldCdzIHJlYWQgYW5kIGNoZWNrIHRoZSB1bmNsZWFuZWQgZGF0YToKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGV2YWw9Rn0KIyByZWFkIHRoZSByYXcgZGF0YQpyYXdfZGF0YSA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YSIsInJhd19kYXRhX2V4cDEuY3N2IikpCmhlYWQocmF3X2RhdGEpCmBgYAoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0KIyByZWFkIHRoZSByYXcgZGF0YQpyYXdfZGF0YSA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YSIsInJhd19kYXRhX2V4cDEuY3N2IikpCgprbml0cjo6a2FibGUoaGVhZChyYXdfZGF0YSkpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiwgImNvbmRlbnNlZCIpLCBmaXhlZF90aGVhZCA9IFQsIGZ1bGxfd2lkdGggPSBGKSU+JQogIHNjcm9sbF9ib3god2lkdGggPSAiNzgwcHgiKQpgYGAKCiMjIyBFeGVyY2lzZQoKVGhlcmUgaXMgYSBkYXRhc2V0IGluIHRoZSBgY2xlYW5lZF9kYXRhYCBmb2xkZXIgbmFtZWQgYHVuaWNlZl91NW1yLmNzdmAuIFJlYWQgdGhlIGRhdGFzZXQgdXNpbmcgYHJlYWRfY3N2YCBhbmQgYGhlcmVgLgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KdW5pY2VmX2RhdGEgPC0gcmVhZF9jc3YoaGVyZSgiY2xlYW5lZF9kYXRhIiwidW5pY2VmX3U1bXIuY3N2IikpCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI3MDBweCIsIG91dC5oZWlnaHQ9IjM1MHB4IiwgZmlnLmNhcD0gIkFydHdvcmsgYnkgQWxsaXNvbiBIb3JzdDogaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9zdGF0cy1pbGx1c3RyYXRpb25zIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgnaW5wdXRzJywndGlkeWRhdGFfMy5qcGcnKSkKYGBgCgoKCkluIG9yZGVyIHRvIGNsZWFuIHRoZSBkYXRhLCB3ZSB1c2UgKnRpZHl2ZXJzZSogd2hpY2ggaXMgYSBjb2xsZWN0aW9uIG9mIHBhY2thZ2VzIHRvIHdvcmsgd2l0aCBkYXRhLiBPbmUgb2YgdGhlIHRpZHl2ZXJzZSBwYWNrYWdlcyB0aGF0IHdlIHVzZSByZWd1bGFybHkgaXMgYGRwbHlyYCB3aGljaCBpbmNsdWRlcyBzZXZlcmFsIGZ1bmN0aW9uczoKCi0gYG11dGF0ZSgpYCBhZGRzIG5ldyB2YXJpYWJsZXMgb3IgY2hhbmdlIGV4aXN0aW5nIG9uZXMuCi0gYHNlbGVjdCgpYCBwaWNrIHZhcmlhYmxlcyAoY29sdW1ucykgYmFzZWQgb24gdGhlaXIgbmFtZXMuCi0gYGZpbHRlcigpYCBwaWNrcyBjYXNlcyAocm93cykgYmFzZWQgb24gdGhlaXIgdmFsdWVzLgotIGBzdW1tYXJpc2UoKWAgZ2l2ZXMgYSBzaW5nbGUgc2luZ2xlIHN1bW1hcnkgb2YgdGhlIGRhdGEgKGUuZy4sIG1lYW4sIGNvdW50cywgZXRjLikKLSBgYXJyYW5nZSgpYCBjaGFuZ2VzIHRoZSBvcmRlcmluZyBvZiB0aGUgcm93cy4KLSBgZ3JvdXBfYnkoKWAgZGl2aWRlcyB5b3VyIGRhdGFmcmFtZSBpbnRvIGdyb3VwZWQgZGF0YWZyYW1lcyBhbmQgYWxsb3cgeW91IHRvIGRvIGVhY2ggb2YgdGhlIGFib3ZlIG9wZXJhdGlvbnMgKGV4Y2VwdCBmb3IgYGFycmFuZ2VgKSBvbiBldmVyeSBvbmUgb2YgdGhlbSBzZXBhcmF0ZWx5LgoKUGljayBgc3ViamVjdGAsIGBhZ2VgLCBhbmQgYGdlbmRlcmAgY29sdW1uczoKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBldmFsPUZ9CnNlbGVjdGVkX2RhdGEgPC0gc2VsZWN0KHJhd19kYXRhLCBzdWJqZWN0LCBhZ2UsIGdlbmRlcikKYGBgCgpOb3csIGRvIHRoZSBmb2xsb3dpbmcgdGFza3M6IHBpY2sgYWxsIHRoZSBtYWxlIHBhcnRpY2lwYW50cywgcGljayBhbGwgdGhlIG1hbGUgcGFydGljaXBhbnRzICoqb3IqKiB0aG9zZSBncmVhdGVyIHRoYW4gMjUgeWVhcnMgb2xkLCBhbmQgZmluYWxseSBwaWNrIGFsbCBtYWxlIHBhcnRpY2lwYW50cyAqKmFuZCoqIHRob3NlIGdyZWF0ZXIgdGhhbiAyNSB5ZWFycyBvbGQ6CgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZXZhbD1GfQojIGZpbHRlciBhbGwgbWFsZXMKZmlsdGVyZWRfZGF0YV9tYWxlIDwtIGZpbHRlcihyYXdfZGF0YSwgZ2VuZGVyID09ICJNYWxlIikKIyBmaWx0ZXIgbWFsZXMgYW5kIG9sZGVyIHRoYW4gMjUKZmlsdGVyZWRfZGF0YV9tYWxlX2FuZF9ncmVhdGVyMjUgPC0gZmlsdGVyKHJhd19kYXRhLCBnZW5kZXIgPT0gIk1hbGUiICYgYWdlID4gMjUgKQojIGZpbHRlciBtYWxlcyBvciBvbGRlciB0aGFuIDI1CmZpbHRlcmVkX2RhdGFfbWFsZV9vcl9ncmVhdGVyMjUgPC0gZmlsdGVyKHJhd19kYXRhLCBnZW5kZXIgPT0gIk1hbGUiIHwgYWdlID4gMjUgKQpgYGAKCkFycmFuZ2UgKG9yZGVyKSB5b3VyIGRhdGFmcmFtZSBiYXNlZCBvbiB0aGUgYWdlLCBvbmNlIGluIGFuIGFzY2VuZGluZyBvcmRlciAoeW91bmdlcnMgZmlyc3QpIGFuZCBvbmNlIGJhc2VkIG9uIGRlc2NlbmRpbmcgb3JkZXIgKG9sZGVycyBmaXJzdCk6CgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KIyBvcmRlciBwYXJ0aWNpcGFudHMgYmFzZWQgb24gdGhlaXIgYWdlCmFycmFuZ2VkX2RhdGEgPC0gYXJyYW5nZShyYXdfZGF0YSwgYWdlKQojIG9yZGVyIHBhcnRpY2lwYW50cyBiYXNlZCBvbiB0aGVpciBhZ2UgKGRlc2NlbmRlaW5nKQphcnJhbmdlZF9kYXRhX2Rlc2NlbmRpbmcgPC0gYXJyYW5nZShyYXdfZGF0YSwgZGVzYyhhZ2UpKQpgYGAKCkNyZWF0ZSBhIGNvbHVtbiB0byBzaG93IGlmIHRoZSBwYXJ0aWNpcGFudCBoYXMgZmluaXNoZWQgdGhlIHRhc2sgb3Igbm90OgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9Cm11dGF0ZWRfZGF0YSA8LSBtdXRhdGUgKHJhd19kYXRhLCBmaW5pc2hlZD0gY2FzZV93aGVuKHByb2dyZXNzPT0xMDB+ICJZZXMiLFR+ICJObyIpKQpgYGAKClN1bW1hcml6ZSBwYXJ0aWNpcGFudHMgYWdlIGFuZCBzZDoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnN1bW1hcmlzZShyYXdfZGF0YSwgbWVhbj0gbWVhbihhZ2UsIG5hLnJtPVQpLAogICAgICAgICAgc2Q9IHNkIChhZ2UsIG5hLnJtPVQpKQpgYGAKCkEgbmV3IGZ1bmN0aW9uOiAqKnBpcGUgb3BlcmF0b3JzKiogYCU+JWAgcGlwZXMgYSB2YWx1ZSBpbnRvIHRoZSBuZXh0IGZ1bmN0aW9uOgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnJhd19kYXRhICU+JSAKICBzdW1tYXJpc2UoLiwgbWVhbj0gbWVhbihhZ2UsIG5hLnJtPVQpLAogICAgICAgICAgICBzZD0gc2QgKGFnZSwgbmEucm09VCkpCmBgYAoKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpyYXdfZGF0YSAlPiUgCiAgc3VtbWFyaXNlKG1lYW49IG1lYW4oYWdlLCBuYS5ybT1UKSwKICAgICAgICAgICAgc2Q9IHNkIChhZ2UsIG5hLnJtPVQpKQpgYGAKCkNhbGN1bGF0ZSB0aGUgYWdlIG1lYW4gb2YgeW91bmdlciB0aGFuIDI1IHBhcnRpY2lwYW50cyBvbmx5OgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnJhd19kYXRhICU+JSAKICBmaWx0ZXIgKGFnZSA8IDI1KSAlPiUKICBzdW1tYXJpc2UobWVhbj0gbWVhbihhZ2UsIG5hLnJtPVQpLAogICAgICAgICAgICBzZD0gc2QgKGFnZSwgbmEucm09VCkpCmBgYAoKQ2FsY3VsYXRlIHRoZSBhZ2UgbWVhbiBvZiB5b3VuZ2VyIHRoYW4gMjUgcGFydGljaXBhbnRzICBmb3IgZWFjaCBnZW5kZXIgc2VwYXJhdGVseToKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpyYXdfZGF0YSAlPiUgCiAgZmlsdGVyIChhZ2UgPCAyNSkgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyKSAlPiUKICBzdW1tYXJpc2UobWVhbj0gbWVhbihhZ2UsIG5hLnJtPVQpLAogICAgICAgICAgICBzZD0gc2QgKGFnZSwgbmEucm09VCkpICU+JQogIHVuZ3JvdXAgKCkKYGBgICAgICAgICAgCgoKIyMjIEV4ZXJjaXNlCgoxLiBDcmVhdGUgYSBjb2x1bW4gdG8gc2hvdyBpZiBwYXJ0aWNpcGFudCBpcyBvbGRlciB0aGFuIDIzIG9yIG5vdCBhbmQgdGhlbiBjYWxjdWxhdGUgcmVhc29uaW5nIGFiaWxpdHkgKGByZWFzb25pbmdfdG90YWxgKSBtZWFuIGZvciBlYWNoIGdyb3VwIHNlcGFyYXRlbHk6CmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpyYXdfZGF0YSAlPiUKICBtdXRhdGUoYWdlX2dyb3VwID0gY2FzZV93aGVuKGFnZSA+IDIzIH4gImdyZWF0ZXIgdGhhbiAyMyIsIFR+ICJ5b3VuZ2VyIHRoYW4gMjMiKSkgJT4lCiAgZ3JvdXBfYnkoYWdlX2dyb3VwKSAlPiUKICBzdW1tYXJpc2UocmVhc29uaW5nX3RvdGFsID0gbWVhbihyZWFzb25pbmdfdG90YWwsIG5hLnJtPVQpKQpgYGAgICAgIAoKMi4gQWRkIHRoZSBvcGVuX21pbmRlZG5lc3MgdG90YWwgc2NvcmUgKHN1bSkgdG8gdGhlIGRhdGFmcmFtZSBhbmQgdGhlbiBjb252ZXJ0IHN1YmplY3QgY29sdW1uIHRvIGZhY3RvcjoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9Cm11dGF0ZWRfb3Blbm1pbmRfZGF0YSA8LSByYXdfZGF0YSAlPiUKICBtdXRhdGUob3Blbm1pbmRlZF90b3RhbD0gb3Blbm1pbmRlZDErb3Blbm1pbmRlZDIrb3Blbm1pbmRlZDMrb3Blbm1pbmRlZDQrb3Blbm1pbmRlZDUrb3Blbm1pbmRlZDYrb3Blbm1pbmRlZDcrb3Blbm1pbmRlZDgpICU+JQogIG11dGF0ZShzdWJqZWN0PSBmYWN0b3Ioc3ViamVjdCkpCmBgYCAKCgpOZXh0LCB3ZSB3YW50IHRvIHBpdm90IG91ciBkYXRhIHRvIHN3aXRjaCBiZXR3ZWVuIGxvbmcgYW5kIHdpZGUgZm9ybWF0OgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI3MDBweCIsIG91dC5oZWlnaHQ9IjM1MHB4IiwgZmlnLmNhcD0gIkFydHdvcmsgYnkgQWxsaXNvbiBIb3JzdDogaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9zdGF0cy1pbGx1c3RyYXRpb25zIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgnaW5wdXRzJywndGlkeWRhdGFfMS5qcGcnKSkKYGBgCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KIyBwaXZvdGluZyB5b3VyIGRhdGEKCgojIE1ha2UgeW91IGRhdGEgbG9uZwpsb25nX2RhdGEgPC0gcmF3X2RhdGEgJT4lCiAgc2VsZWN0KHN1YmplY3QsIHN0YWdlMV9zaW1wbGU6c3RhZ2U3X3NpbXBsZSxzdGFnZTFfY29tcGxleDpzdGFnZTdfY29tcGxleCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN0YWdlMV9zaW1wbGU6c3RhZ2U3X2NvbXBsZXgpLCBuYW1lc190byA9ICdzdGFnZScsIHZhbHVlc190byA9ICd0cnV0aF9lc3RpbWF0ZScpCgoKIyBNYWtlIHlvdSBkYXRhIHdpZGUKd2lkZV9kYXRhIDwtIGxvbmdfZGF0YSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc3RhZ2UsIHZhbHVlc19mcm9tPSB0cnV0aF9lc3RpbWF0ZSkKCmBgYAoKIyMjIEV4ZXJjaXNlCgpDb252ZXJ0IHRoZSBVTklDRUYgZGF0YXNldCB0byBsb25nIGFuZCB3aWRlIGZvcm1hdHM6CmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GfQp1bmljZWZfZGF0YSA8LSByZWFkX2NzdihoZXJlKCJjbGVhbmVkX2RhdGEiLCJ1bmljZWZfdTVtci5jc3YiKSkKCmxpYnJhcnkoamFuaXRvcikKdW5pY2VmX2RhdGFfY2xlYW5lZCA8LSB1bmljZWZfZGF0YSAlPiUKICBjbGVhbl9uYW1lcygpCgp1bmljZWZfbG9uZ19kYXRhIDwtIHVuaWNlZl9kYXRhX2NsZWFuZWQgJT4lIHBpdm90X2xvbmdlcihjb2xzID0gYyh1NW1yXzE5NTA6dTVtcl8yMDE1KSwgbmFtZXNfdG8gPSAneWVhcicsIHZhbHVlc190byA9ICd1NW1yJykKdW5pY2VmX3dpZGVnX2RhdGEgPC0gdW5pY2VmX2xvbmdfZGF0YSAlPiUgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICd5ZWFyJywgdmFsdWVzX2Zyb20gPSAndTVtcicpCmBgYAoKKk5vdGUqOiBUaGUgY29kZXMgZm9yIHRoZSBwcmV2aW91cyBleGVyY2lzZSB3ZXJlIHRha2VuIGZyb20gW3RoaXMgYmxvZyBwb3N0XShodHRwczovL3NlamRlbXlyLmdpdGh1Yi5pby9yLXR1dG9yaWFscy9iYXNpY3Mvd2lkZS1hbmQtbG9uZy8pIHdyaXR0ZW4gYnkgU2ltb24gRWpkZW15ci4KCk5vdywgbGV0J3MgZG8gc29tZSBjbGVhbmluZyB1c2luZyBgZHBseXJgLCBgdGlkeXJgIGFuZCBvdGhlciBgdGlkeXZlcnNlYCBsaWJyYXJpZXM6IApgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZXZhbD1GfQpjbGVhbmVkX2RhdGEgPC0gcmF3X2RhdGEgJT4lIAogIGZpbHRlcihwcm9ncmVzcyA9PSAxMDApICU+JSAjIGZpbHRlciBvdXQgdW5maW5pc2hlZCBwYXJ0aWNpcGFudHMKICBzZWxlY3QoLWVuZF9kYXRlLCAtc3RhdHVzLC1pcF9hZGRyZXNzLCAtZHVyYXRpb25faW5fc2Vjb25kcywgLXJlY29yZGVkX2RhdGU6LXVzZXJfbGFuZ3VhZ2UpICU+JSAjcmVtb3ZlIHNvbWUgdXNlbGVzcyBjb2x1bW5zCiAgbXV0YXRlKG9wZW5taW5kZWRfdG90YWw9IG9wZW5taW5kZWQxK29wZW5taW5kZWQyK29wZW5taW5kZWQzK29wZW5taW5kZWQ0K29wZW5taW5kZWQ1K29wZW5taW5kZWQ2K29wZW5taW5kZWQ3K29wZW5taW5kZWQ4KSAlPiUjIGNyZWF0ZSBhIHRvdGFsIHNjb3JlIGZvciBvdXIgcXVlc3Rpb25uYWlyZQogIG11dGF0ZSh0aGlua2luZzE9IGNhc2Vfd2hlbih0aGlua2luZzE9PTR+IDEsVH4wKSwKICAgICAgICAgdGhpbmtpbmcyPSBjYXNlX3doZW4odGhpbmtpbmcyPT0xMH4gMSxUfjApLAogICAgICAgICB0aGlua2luZzM9IGNhc2Vfd2hlbih0aGlua2luZzM9PTM5fiAxLFR+MCksCiAgICAgICAgIHRoaW5raW5nX3RvdGFsPSB0aGlua2luZzEgKyB0aGlua2luZzIgKyB0aGlua2luZzMpICU+JQogIHNlbGVjdCgtdGhpbmtpbmcxOi1vcGVubWluZGVkOCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN0YWdlMV9zaW1wbGU6c3RhZ2U3X3NpbXBsZSxzdGFnZTFfY29tcGxleDpzdGFnZTdfY29tcGxleCksbmFtZXNfdG8gPSAnc3RhZ2UnLHZhbHVlc190byA9ICd0cnV0aF9lc3RpbWF0ZScpICU+JSAjIG1ha2Ugb3VyIGRhdGFmcmFtZSBsb25nCiAgI3Bpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzdGFnZSwgdmFsdWVzX2Zyb209IHRydXRoX2VzdGltYXRlKSAjIHRoaXMgY29kZSBjaGFuZ2Ugb3VyIGRhdGFmcmFtZSBiYWNrIHRvIHdpZGUKICBmaWx0ZXIoIWlzLm5hKHRydXRoX2VzdGltYXRlKSkgJT4lICNyZW1vdmUgcm93cyB3aXRoIHRydXRoX2VzdGltYXRlID09IE5BCiAgbXV0YXRlKHN0YWdlPSBnc3ViKCJfLioiLCAiIiwgc3RhZ2UpKSAlPiUKICByZW5hbWUoY29uc2VudD0gY29uc2VudF9mb3JtKSAjIHJlbmFtZSBhIGNvbHVtbgpgYGAKCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZWNobz1GfQpjbGVhbmVkX2RhdGEgPC0gcmF3X2RhdGEgJT4lIAogIGZpbHRlcihwcm9ncmVzcyA9PSAxMDApICU+JSAjIGZpbHRlciBvdXQgdW5maW5pc2hlZCBwYXJ0aWNpcGFudHMKICBzZWxlY3QoLWVuZF9kYXRlLCAtc3RhdHVzLC1pcF9hZGRyZXNzLCAtZHVyYXRpb25faW5fc2Vjb25kcywgLXJlY29yZGVkX2RhdGU6LXVzZXJfbGFuZ3VhZ2UpICU+JSAjcmVtb3ZlIHNvbWUgdXNlbGVzcyBjb2x1bW5zCiAgbXV0YXRlKG9wZW5taW5kZWRfdG90YWw9IG9wZW5taW5kZWQxK29wZW5taW5kZWQyK29wZW5taW5kZWQzK29wZW5taW5kZWQ0K29wZW5taW5kZWQ1K29wZW5taW5kZWQ2K29wZW5taW5kZWQ3K29wZW5taW5kZWQ4KSAlPiUjIGNyZWF0ZSBhIHRvdGFsIHNjb3JlIGZvciBvdXIgcXVlc3Rpb25uYWlyZQogIG11dGF0ZSh0aGlua2luZzE9IGNhc2Vfd2hlbih0aGlua2luZzE9PTR+IDEsVH4wKSwKICAgICAgICAgdGhpbmtpbmcyPSBjYXNlX3doZW4odGhpbmtpbmcyPT0xMH4gMSxUfjApLAogICAgICAgICB0aGlua2luZzM9IGNhc2Vfd2hlbih0aGlua2luZzM9PTM5fiAxLFR+MCksCiAgICAgICAgIHRoaW5raW5nX3RvdGFsPSB0aGlua2luZzEgKyB0aGlua2luZzIgKyB0aGlua2luZzMpICU+JQogIHNlbGVjdCgtdGhpbmtpbmcxOi1vcGVubWluZGVkOCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN0YWdlMV9zaW1wbGU6c3RhZ2U3X3NpbXBsZSxzdGFnZTFfY29tcGxleDpzdGFnZTdfY29tcGxleCksbmFtZXNfdG8gPSAnc3RhZ2UnLHZhbHVlc190byA9ICd0cnV0aF9lc3RpbWF0ZScpICU+JSAjIG1ha2Ugb3VyIGRhdGFmcmFtZSBsb25nCiAgI3Bpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzdGFnZSwgdmFsdWVzX2Zyb209IHRydXRoX2VzdGltYXRlKSAjIHRoaXMgY29kZSBjaGFuZ2Ugb3VyIGRhdGFmcmFtZSBiYWNrIHRvIHdpZGUKICBmaWx0ZXIoIWlzLm5hKHRydXRoX2VzdGltYXRlKSkgJT4lICNyZW1vdmUgcm93cyB3aXRoIHRydXRoX2VzdGltYXRlID09IE5BCiAgbXV0YXRlKHN0YWdlPSBnc3ViKCJfLioiLCAiIiwgc3RhZ2UpKSAlPiUKICByZW5hbWUoY29uc2VudD0gY29uc2VudF9mb3JtKQoKa25pdHI6OmthYmxlKGhlYWQoY2xlYW5lZF9kYXRhKSkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IEYpJT4lCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICI3ODBweCIpCmBgYAoKT2ssIG5vdyB0aGUgZGF0YSBpcyBjbGVhbiBhbmQgdGlkeSB3aGljaCBtZWFuczoKCj4gMS4gRWFjaCB2YXJpYWJsZSBmb3JtcyBhIGNvbHVtbi4KMi4gRWFjaCBvYnNlcnZhdGlvbiBmb3JtcyBhIHJvdy4KMy4gRWFjaCB0eXBlIG9mIG9ic2VydmF0aW9uYWwgdW5pdCBmb3JtcyBhIHRhYmxlIChbV2lja2hhbV0oaHR0cHM6Ly92aXRhLmhhZC5jby5uei9wYXBlcnMvdGlkeS1kYXRhLnBkZiksIDIwMTQpLgoKCkNoZWNrIHRoZSBkYXRhZnJhbWUgYW5kIGFsbCB0aGUgZGF0YSB0eXBlczoKYGBge3J9CnN0cihjbGVhbmVkX2RhdGEpCmBgYAoKRmluYWxseSwgd2Ugc2F2ZSBvdXIgZGF0YSB0byB0aGUgYGNsZWFuZWRfZGF0YWAgZm9sZGVyLgoKYGBge3J9CndyaXRlX2NzdihjbGVhbmVkX2RhdGEsIGhlcmUoImNsZWFuZWRfZGF0YSIsImNsZWFuZWRfZGF0YV9leHAxLmNzdiIpKQpgYGAKCiMgRGVzY3JpcHRpdmUgU3RhdGlzdGljcwoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI3MDBweCIsIG91dC5oZWlnaHQ9IjM1MHB4IiwgZmlnLmNhcD0gIkFydHdvcmsgYnkgQWxsaXNvbiBIb3JzdDogaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9zdGF0cy1pbGx1c3RyYXRpb25zIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgnaW5wdXRzJywnbm90X25vcm1hbC5wbmcnKSkKYGBgCgo+IE5vdGU6IEFsbCB0aGUgZGF0YSB0aGF0IHdlIHVzZSBoZXJlIGlzIG1hbmlwdWxhdGVkIChmYWJyaWNhdGVkKSBmb3IgdGVhY2hpbmcgcHVycHVzZXMuIEluIG91ciBzdHVkeSwgd2UgZmFpbGVkIHRvIGZpbmQgc3VjaCBiZWF1dGlmdWwgYW5kIGludGVyZXN0aW5nIHJlc3VsdHMuCgpOb3csIGxldCdzIGRvIHNvbWUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcy4gTm93LCB3ZSBjYW4gb3BlbiBhIG5ldyBzY3JpcHQgY2FsbGVkIGBkYXRhX2FuYWx5c2lzLnJgIGFuZCByZWFkIHNvbWUgZGF0YXNldHMuIFRoZW4gd2UgdXNlIGBza2ltcmAgcGFja2FnZSB0byBkZXNjcmliZSBvdXIgZGF0YS4KCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLH0KbmFyY2lzc2lzbV9kYXRhIDwtIHJlYWRfY3N2KGhlcmUoImNsZWFuZWRfZGF0YSIsIm5hcmNpc3Npc21fZGF0YS5jc3YiKSkKbmFyY2lzc2lzbV9kYXRhICU+JSBza2ltcjo6c2tpbSgpCmBgYAoKIyMjIEV4ZXJjaXNlCgoxLiBPcGVuIHRoZSBkYXRhc2V0IGNhbGxlZCBgdHJlYXRtZW50X2RhdGEuY3N2YCBpbiB0aGUgY2xlYW5lZF9kYXRhIGZvbGRlciBhbmQgZG8gYSBkZXNjcmlwdGl2ZSBhbmFseXNpczoKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GfQp0cmVhdG1lbnRfZGF0YSA8LSByZWFkX2NzdihoZXJlKCJjbGVhbmVkX2RhdGEiLCJ0cmVhdG1lbnRfZGF0YS5jc3YiKSkKdHJlYXRtZW50X2RhdGEgJT4lIHNraW1yOjpza2ltKCkKYGBgCgoyLiBEbyB0aGUgc2FtZSB0aGluZyBmb3IgdGhlIGBtZW1vcnlfZGF0YS5jc3ZgLgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9Cm1lbW9yeV9kYXRhIDwtIHJlYWRfY3N2KGhlcmUoImNsZWFuZWRfZGF0YSIsIm1lbW9yeV9kYXRhLmNzdiIpKQptZW1vcnlfZGF0YSAlPiUgZ3JvdXBfYnkodGltZSkgJT4lCiAgc2tpbXI6OnNraW0oKQpgYGAKCk5vdywgbGV0J3MgZGVzY3JpYmUgb3VyIGV4cGVyaW1lbnQgZGF0YS4gQmUgY2FyZWZ1bCwgd2UgbmVlZCBzb21lIGRhdGEgcmVzaGFwaW5nIGJlZm9yZSBkZXNjcmlwdGlvbjoKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLH0KZGF0YV9leHAxX29yaWcgPC0gcmVhZF9jc3YoaGVyZSgiY2xlYW5lZF9kYXRhIiwiY2xlYW5lZF9kYXRhX2V4cDEuY3N2IikpCgoKZGF0YV9leHAxIDwtIGRhdGFfZXhwMV9vcmlnJT4lIAogICNtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBmYWN0b3IpICU+JQogIG11dGF0ZShzdWJqZWN0PSBmYWN0b3Ioc3ViamVjdCksICMgY29udmVydCBhbGwgY2hhcmFjdGVycyB0byBmYWN0b3IKICAgICAgICAgZ3JvdXAgPSBmYWN0b3IoZ3JvdXApLAogICAgICAgICBzdGFnZSA9IGZhY3RvcihzdGFnZSkpCmBgYAoKSG93IG1hbnkgcGFydGljaXBhbnRzIGluIHRvdGFsPwoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGV2YWw9Rn0KZGF0YV9leHAxICU+JSBzdW1tYXJpc2Uobj0gbl9kaXN0aW5jdChzdWJqZWN0KSkKYGBgCgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0KZGF0YV9leHAxICU+JSBzdW1tYXJpc2Uobj0gbl9kaXN0aW5jdChzdWJqZWN0KSklPiUKICBrbml0cjo6a2FibGUoKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpCmBgYAoKaG93IG1hbnkgcGFydGljaXBhbnRzIGluIGVhY2ggZ3JvdXA/CmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBldmFsPUZ9CmRhdGFfZXhwMSAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCk9PTEpICU+JSAKICB1bmdyb3VwICgpICU+JSAKICBncm91cF9ieShncm91cCkgJT4lIAogIGNvdW50KCkgCmBgYAoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0KZGF0YV9leHAxICU+JSBncm91cF9ieShzdWJqZWN0KSAlPiUgZmlsdGVyKHJvd19udW1iZXIoKT09MSkgJT4lIHVuZ3JvdXAgKCkgJT4lIGdyb3VwX2J5KGdyb3VwKSAlPiUgY291bnQoKSAlPiUKICBrbml0cjo6a2FibGUoKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgZml4ZWRfdGhlYWQgPSBUKQpgYGAKCkZpbmQgdGhlIG1lYW4gYW5kIHNkIGZvciBudW1lcmljIHZhcmlhYmxlcyB1c2luZyBiYXNlIFIgYHN1bW1hcnlgIGZ1bmN0aW9uOgoKYGBge3J9CmRhdGFfZXhwMSAlPiUgCiAgZ3JvdXBfYnkoc3ViamVjdCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCk9PTEpICU+JSAKICB1bmdyb3VwICgpICU+JQogIHN1bW1hcnkoKQpgYGAKCkFsdGVybmF0aXZlbHksIHdlIGNhbiB1c2UgYGJhc2UgUiBgc3VtbWFyeWAgZnVuY3Rpb25gc2tpbXJgIGxpYnJhcnk6CmBgYHtyIGV2YWw9Rn0KZGF0YV9leHAxICU+JSAKICBncm91cF9ieShzdWJqZWN0KSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoKT09MSkgJT4lIAogIHVuZ3JvdXAgKCkgJT4lIAogIGRwbHlyOjpzZWxlY3QgKGFnZSwgbnVtZXJhY3lfdG90YWwsIHJlYXNvbmluZ190b3RhbCwgb3Blbm1pbmRlZF90b3RhbCwgdGhpbmtpbmdfdG90YWwpICU+JSAKICBza2ltcjo6c2tpbSgpCmBgYAoKYGBge3IgZWNobz1GfQpkYXRhX2V4cDEgJT4lIAogIGdyb3VwX2J5KHN1YmplY3QpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpPT0xKSAlPiUgCiAgdW5ncm91cCAoKSAlPiUgCiAgZHBseXI6OnNlbGVjdCAoYWdlLCBudW1lcmFjeV90b3RhbCwgcmVhc29uaW5nX3RvdGFsLCBvcGVubWluZGVkX3RvdGFsLCB0aGlua2luZ190b3RhbCkgJT4lIAogIHNraW1yOjpza2ltKCkgJT4lCiAga25pdHI6OmthYmxlKCkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IEYpJT4lCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICI3ODBweCIpCmBgYAoKCiMjIyBFeGVyY2lzZQoKRm9yIHRoaXMgZXhlcmNpc2UsIHdlIHVzZSBhIGRhdGFzZXQgb2Ygb25lIG9mIG15IG93biBzdHVkaWVzLiBJbiB0aGlzIHN0dWR5LCB3ZSBhc2tlZCBwYXJ0aWNpcGFudHMgdG8gZ3Vlc3MgdGhlIHBoeXNpY2FsIGJyaWdodG5lc3Mgb2YgcmVhc29uaW5nIGFyZ3VtZW50cyBhbmQgdGhlbiB3ZSBnYXZlIGEgY29nbml0aXZlIGFiaWxpdHkgdGVzdC4gKFNlZSB0aGUgb3JpZ2luYWwgc3R1ZHkgW2hlcmVdKGh0dHBzOi8vb3NmLmlvL2VieG5mLykpLiBPcGVuIGBnaGFzZW1pX2JyaWdodG5lc3NfZXhwNC5jc3ZgIGZpbGUgYW5kIGFuc3dlciB0byB0aGUgZm9sbG93aW5nIHF1ZXN0aW9uczoKCjEuIEhvdyBtYW55IHBhcnRpY2lwYW50cyBkaWQgd2UgdGVzdCBpbiB0b3RhbD8KMi4gRmluZCBvdXQgaG93IG1hbnkgbWFsZSBhbmQgZmVtYWxlIHdlIHRlc3RlZC4KMy4gQ2FsY3VsYXRlIG1lYW4gYW5kIHNkIGZvciBhZ2UgYW5kIGNvZ25pdGl2ZSBhYmlsaXR5IChgY29nX2FiaWxpdHlgKS4KCgpgYGB7ciB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KZ2hhc2VtaV9kYXRhIDwtIHJlYWRfY3N2KGhlcmUoImNsZWFuZWRfZGF0YSIsImdoYXNlbWlfYnJpZ2h0bmVzc19leHA0LmNzdiIpKQoKZ2hhc2VtaV9kYXRhICU+JSBzdW1tYXJpc2UobiA9IG5fZGlzdGluY3QocGFydGljaXBhbnQpKSAjIG51bWJlciBvZiBwYXJ0aWNpcGFudHM6MjAwCgpnaGFzZW1pX2RhdGEgJT4lIGdyb3VwX2J5IChwYXJ0aWNpcGFudCkgJT4lIGZpbHRlciAocm93X251bWJlcigpPT0xKSAlPiUgZ3JvdXBfYnkgKGdlbmRlcikgJT4lIHN1bW1hcmlzZShuPSBuKCkpICU+JSB1bmdyb3VwKCkgIyAxODMgZmVtYWxlLCAxNyBtYWxlCgpnaGFzZW1pX2RhdGEgJT4lIGRwbHlyOjpzZWxlY3QgKGFnZSwgY29nX2FiaWxpdHkpICU+JSBza2ltcjo6c2tpbSgpICMgbWVhbiBhbmQgc2QgZm9yIGFnZSBhbmQgY29nbml0aXZlIGFiaWxpdHkKYGBgCgoKIyBEYXRhIFZpc3VhbGl6YXRpb24KCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNzAwcHgiLCBvdXQuaGVpZ2h0PSIzNTBweCIsIGZpZy5jYXA9ICJBcnR3b3JrIGJ5IEFsbGlzb24gSG9yc3Q6IGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3Qvc3RhdHMtaWxsdXN0cmF0aW9ucyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ2dncGxvdDJfbWFzdGVycGllY2UucG5nJykpCmBgYAoKCkJlZm9yZSBzdGFydGluZyB0aGUgZ2dwbG90LCBsZXRzIHRyeSBhIHZpc3VhbGl6YXRpb24gdXNpbmcgYSBmdW5jdGlvbiBmcm9tIHRoZSBCYXNlIFIgdGhlIHBsb3QoKSBmdW5jdGlvbiBzaG93cyB0aGUgYXNzb2NpYXRpb24gb2YgZWFjaCB2YXJpYWJsZSBhZ2FpbnN0IHRoZSBvdGhlciBvbmUgaW4gYSBkYXRhIGhhbmR5IGZvciBkYXRhIHdpdGggZmV3IG51bWJlciBvZiB2YXJpYWJsZXMgdG8gc2VlIGlmIHRoZXJlIGFyZSBhbnkgcGF0dGVybnMKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBkcGk9IDMwMCwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KCmV4YW1fZGF0YTwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImNsZWFuZWRfZGF0YSIsICJleGFtX2RhdGEuY3N2IikpCgpwbG90KHggPSBleGFtX2RhdGEkQW54aWV0eSwgeSA9IGV4YW1fZGF0YSRFeGFtKQoKYGBgCgpUaGUgY29kZSBhbHNvIHdvcmtzIHdpdGhvdXQgd3JpdGluZyB4IGFuZCB5LCBob3dldmVyLCB3cml0aW5nIHRoZW0gaXMgc3Ryb25nbHkgcmVjb21tZW5kZWQKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBkcGk9IDMwMCwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KCnBsb3QoZXhhbV9kYXRhJEFueGlldHksIGV4YW1fZGF0YSRFeGFtKQpgYGAKCmBnZ3Bsb3RgLCB0aGUgZ2cgaW4gZ2dwbG90IHN0YW5kcyBmb3IgZ3JhbW1hciBvZiBncmFwaGljcy4gR3JhbW1hciBvZiBncmFwaGljcyBiYXNpY2FsbHkgc2F5cyBhbnkgZ3JhcGhpY2FsIHJlcHJlc2VudGF0aW9uIG9mIGRhdGEsIGNhbiBiZSBwcm9kdWNlZCBieSBhIHNlcmllcyBvZiBsYXllcnMuIFlvdSBjYW4gdGhpbmsgb2YgYSBsYXllciBhcyBhIHBsYXN0aWMgdHJhbnNwYXJlbmN5LiBMZXRzIGRyYXcgdGhlIHNhbWUgcGxvdCB1c2luZyBnZ3Bsb3QuIEFsd2F5cywgbWVudGlvbiB0aGUgZGF0YSB3ZSBhcmUgZ29pbmcgdG8gd29yayB3aXRoLgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZHBpPSAzMDAsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTV9CmdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeCA9IEV4YW0sIHkgPSBBbnhpZXR5KSkKYGBgCgoKLSBgYWVzYDogYWVzIHdoaWNoIHN0YW5kcyBmb3IgYWVzdGhldGljcyBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgdmFyaWFibGUgaW4geW91ciBkYXRhc2V0IGFuZCBhbiBhc3BlY3Qgb2YgdGhlIHBsb3QgdGhhdCBpcyBnb2luZyB0byB2aXN1YWxseSBjb252ZXkgdGhlIGluZm9ybWF0aW9uIHRvIHRoZSByZWFkZXIKCi0gVmlzdWFsIGVsZW1lbnRzIGFyZSBrbm93biBhcyBnZW9tcyAoc2hvcnQgZm9yICdnZW9tZXRyaWMgb2JqZWN0cycpIGluIGdncGxvdCAyLiBXaGVuIHdlIGRlZmluZSBhIGxheWVyLCB3ZSBoYXZlIHRvIHRlbGwgUiB3aGF0IGdlb20gd2Ugd2FudCBkaXNwbGF5ZWQgb24gdGhhdCBsYXllciAoZG8gd2Ugd2FudCBhIGJhciwgbGluZSBkb3QsIGV0Yy4/KQoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBFeGFtLCB5ID0gQW54aWV0eSkpKyBnZW9tX3BvaW50KCkKYGBgCgpTbywgbGV0cyB0cnkgc29tZSBvZiB0aGVtIGhlcmUgbGlrZSBzaGFwZSBhbmQgc2l6ZS4gQmUgY2FyZWZ1bCB3aXRoIHRoZSArIHNpZ24sIGlmIHlvdSBjbGluayBlbnRlciBmb3IgdGhlIG5leHQgcGFydCBvZiB0aGUgY29kZSwgdGhlICsgc2lnbiBzaG91bGQgbm90IGdvIHRvIHRoZSBuZXh0IGxpbmUKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBkcGk9IDMwMCwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KZ2dwbG90KGRhdGEgPSBleGFtX2RhdGEsIGFlcyh4ID0gRXhhbSwgeSA9IEFueGlldHkpKSsKICBnZW9tX3BvaW50KHNpemUgPSAyLCBzaGFwZSA9IDgpCmBgYAoKVGhlIGN1cnJlbnQgcGxvdCBpcyBub3QgdmVyeSBpbmZvcm1hdGl2ZSBhYm91dCB0aGUgcGF0dGVybnMgZm9yIGVhY2ggZ2VuZGVyLgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZHBpPSAzMDAsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTV9CmdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeCA9IEV4YW0sIHkgPSBBbnhpZXR5LCBjb2xvciA9IEdlbmRlcikpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIHNoYXBlID0gMTApCgpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBFeGFtLCB5ID0gQW54aWV0eSwgY29sb3IgPSBHZW5kZXIsIHNoYXBlID0gR2VuZGVyKSkrCiAgZ2VvbV9wb2ludChzaXplID0gMiwgc2hhcGUgPSAxMCkKYGBgCgpRdWVzdGlvbjogd2h5IHRoZSBhYm92ZSBjb2RlIGRvZXNuJ3QgbWFrZSBhbnkgY2hhbmdlPwoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBFeGFtLCB5ID0gQW54aWV0eSwgY29sb3IgPSBHZW5kZXIsIHNoYXBlID0gR2VuZGVyKSkrCiAgZ2VvbV9wb2ludChzaXplID0gMikKYGBgCgpDYW4gYXNzaWduIHRoZSBmaXJzdCBsYXllciB0byBhIHZhcmlhYmxlIHRvIHJlZHVjZSB0aGUgbGVuZ3RoIG9mIGNvZGVzIGZvciBuZXh0IGxheWVycy4KCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBkcGk9IDMwMCwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KTXlfZ3JhcGggPC0gZ2dwbG90KGRhdGEgPSBleGFtX2RhdGEsIGFlcyh4ID0gRXhhbSwgeSA9IEFueGlldHkpKQoKTXlfZ3JhcGggKyBnZW9tX3BvaW50KCkKYGBgCgpsZXRzIGFkZCBhIGxpbmUgdG8gdGhlIGN1cnJlbnQgZ3JhcGgKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpNeV9ncmFwaCArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkKYGBgCgpBZXN0aGV0aWNzIGNhbiBiZSBzZXQgZm9yIGFsbCBsYXllcnMgb2YgdGhlIHBsb3QgKGkuZS4sIGRlZmluZWQgaW4gdGhlIHBsb3QgYXMgYSB3aG9sZSkgb3IgY2FuIGJlIHNldCBpbmRpdmlkdWFsbHkgZm9yIGVhY2ggZ2VvbSBpbiBhIHBsb3QuCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZHBpPSAzMDAsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTV9Ck15X2dyYXBoICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBHZW5kZXIpKSArIGdlb21fc21vb3RoKCkKCk15X2dyYXBoICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBHZW5kZXIpKSArIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IEdlbmRlcikpCmBgYAoKVGhlIHNoYWRlZCBhcmVhIGFyb3VuZCB0aGUgbGluZSBpcyB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYXJvdW5kIHRoZSBsaW5lLiBXZSBjYW4gc3dpdGNoIHRoaXMgb2ZmIGJ5ICBhZGRpbmcgYHNlID0gRmAgKHdoaWNoIGlzIHNob3J0IGZvciAnc3RhbmRhcmQgZXJyb3IgPSBGYWxzZScpCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZHBpPSAzMDAsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTV9Ck15X2dyYXBoICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoc2UgPSBGKQpgYGAKCgpXaGF0IGlmIHdlIHdhbnQgb3VyIGxpbmUgdG8gYmUgYSBkaXJlY3QgbGluZT8KYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpNeV9ncmFwaCArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKHNlID0gRiwgbWV0aG9kID0gbG0pCgpgYGAKSG93IHRvIGNoYW5nZSB0aGUgbGFiZWxzIG9mIHggYW5kIHkgYXhlcz8KYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpNeV9ncmFwaCArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKHNlID0gRiwgbWV0aG9kID0gbG0pICsKICBsYWJzKHggPSAiRXhhbSBzY29yZXMgJSIsIHkgPSAiQW54aWV0eSBzY29yZXMiKQpgYGAKCkhpc3RvZ3JhbXMgYXJlIHVzZWQgdG8gc2hvdyBkaXN0cmlidXRpb25zIG9mIHZhcmlhYmxlcyB3aGlsZSBiYXIgY2hhcnRzIGFyZSB1c2VkIHRvIGNvbXBhcmUgdmFyaWFibGVzLiBIaXN0b2dyYW1zIHBsb3QgcXVhbnRpdGF0aXZlIGRhdGEgd2l0aCByYW5nZXMgb2YgdGhlIGRhdGEgZ3JvdXBlZCBpbnRvIGJpbnMgb3IgaW50ZXJ2YWxzIHdoaWxlIGJhciBjaGFydHMgcGxvdCBjYXRlZ29yaWNhbCBkYXRhLgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQojZ2dwbG90KGRhdGEgPSBleGFtX2RhdGEsIGFlcyh4ID0gQW54aWV0eSwgeSA9IEV4YW0gKSkgKyBnZW9tX2hpc3RvZ3JhbSgpCiMgdGhlIGNvZGUgYWJvdmUgZ2l2ZXMgYW4gZXJyb3IgYXMgZ2VvbV9oaXN0b2dyYW0gY2FuIG9ubHkgaGF2ZSB4IG9yIHkgYXhpcyBpbiBpdHMgYWVzKCkKCmdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeCA9IEFueGlldHkpKSArIGdlb21faGlzdG9ncmFtKCkKCmdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeSA9IEFueGlldHkpKSArIGdlb21faGlzdG9ncmFtKCkKCmdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeCA9IEFueGlldHkpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMSkKCmdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeCA9IEFueGlldHkpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMSwgZmlsbCA9ICJncmVlbiIpCgpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBBbnhpZXR5KSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzEsIGZpbGwgPSAiZ3JlZW4iLCBjb2wgPSAicmVkIikKYGBgCgpMZXQncyBzdG9wIHVzaW5nIHRoZSBNeV9ncmFwaCB2YXJpYWJsZSBhbmQgd3JpdGUgdGhlIHdob2xlIGNvZGUgZnJvbSB0aGUgc3RhcnQgYWdhaW4gZm9yIGEgYmFyIGNoYXJ0CmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBkcGk9IDMwMCwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KZ2dwbG90KGRhdGEgPSBleGFtX2RhdGEsIGFlcyh4ID0gU2xlZXBfcXVhbGl0eSkpKwogIGdlb21fYmFyKCkKYGBgCkJlY2F1c2Ugd2Ugd2FudCB0byBwbG90IGEgc3VtbWFyeSBvZiB0aGUgZGF0YSAodGhlIG1lYW4pIHJhdGhlciB0aGFuIHRoZSByYXcgc2NvcmVzIHRoZW1zZWx2ZXMsIHdlIGhhdmUgdG8gdXNlIGEgc3RhdC4KYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBTbGVlcF9xdWFsaXR5LCB5ID0gRXhhbSwgZmlsbCA9IEdlbmRlcikpKwogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIikKCgpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBTbGVlcF9xdWFsaXR5LCB5ID0gRXhhbSwgZmlsbCA9IEdlbmRlcikpKwogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgcG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKClRoZSBvdGhlciB3YXkgdG8gZ2V0IHRoZSBzYW1lIHBsb3QgdGhhdCB0aGUgY29kZSBhYm92ZSBnaXZlcywgaXMgdXNpbmcgdGhlIHN0YXRfc3VtbWFyeSBmdW5jdGlvbiB0aGF0IHRha2VzIHRoZSBmb2xsb3dpbmcgZ2VuZXJhbCBmb3JtOiBgc3RhdF9zdW1tYXJ5KGZ1bmN0aW9uID0geCwgZ2VvbSA9IHkpYAoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQpnZ3Bsb3QoZGF0YSA9IGV4YW1fZGF0YSwgYWVzKHggPSBTbGVlcF9xdWFsaXR5LCB5ID0gRXhhbSwgZmlsbCA9IEdlbmRlcikpKwogIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLCBnZW9tID0gImJhciIsIHBvc2l0aW9uID0gImRvZGdlIikKYGBgCkhvdyB0byBjb21iaW5lIG11bHRpcGxlIHBsb3RzPyBIb3cgdG8gY29tYmluZSBtdWx0aXBsZSBwbG90cz8gV2UgY2FuIHVzZSB0aGUgYHBhdGNod29ya2AgcGFja2FnZS4gQSBuaWNlIHR1dG9yaWFsIG9uIHVzaW5nIHRoaXMgcGFja2FnZSBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vcGF0Y2h3b3JrLmRhdGEtaW1hZ2luaXN0LmNvbS9hcnRpY2xlcy9wYXRjaHdvcmsuaHRtbCkKCmBgYHtyIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBkcGk9IDMwMCwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KcDEgPSBNeV9ncmFwaCArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gR2VuZGVyKSkgKyBnZW9tX3Ntb290aCgpCgpwMiA9IGdncGxvdChkYXRhID0gZXhhbV9kYXRhLCBhZXMoeCA9IEFueGlldHkpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMSkKCnAzID0gZ2dwbG90KGRhdGEgPSBleGFtX2RhdGEsIGFlcyh4ID0gU2xlZXBfcXVhbGl0eSwgeSA9IEV4YW0sIGZpbGwgPSBHZW5kZXIpKSsKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJiYXIiLCBwb3NpdGlvbiA9ICJkb2RnZSIpCgpwNCA9IE15X2dyYXBoICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoc2UgPSBGLCBtZXRob2QgPSBsbSkgKwogIGxhYnMoeCA9ICJFeGFtIHNjb3JlcyAlIiwgeSA9ICJBbnhpZXR5IHNjb3JlcyIpCgpjb21iaW5lZCA9IHAxICsgcDIrIHAzICsgcDQgKyBwbG90X2xheW91dChucm93ID0gNCwgYnlyb3cgPSBGKQoKY29tYmluZWQKCnAxIHwgcDIgLyBwMyAvIHA0CgpwMSB8IHAyIC8gKHAzIC8gcDQpCmBgYAoKYGdnc2F2ZSgpYCBmdW5jdGlvbiwgd2hpY2ggaXMgYSB2ZXJzYXRpbGUgZXhwb3J0aW5nIGZ1bmN0aW9uIHRoYXQgY2FuIGV4cG9ydCBhcyBQb3N0U2NyaXB0ICguZXBzLy5wcyksIHRleCAocGljdGV4KSwgcGRmLCBqcGVnLCB0aWZmLCBwbmcsIGJtcCwgc3ZnIGFuZCB3bWYgKGluIFdpbmRvd3Mgb25seSkuIEluIGl0cyBiYXNpYyBmb3JtLCB0aGUgc3RydWN0dXJlIG9mIHRoZSBmdW5jdGlvbiBpcyB2ZXJ5IHNpbXBsZTogYGdnc2F2ZShmaWxlbmFtZSlgCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZHBpPSAzMDAsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTV9Cmdnc2F2ZShjb21iaW5lZCwgZmlsZW5hbWUgPSBoZXJlKCJvdXRwdXRzIiwgImNvbWJpbmVkLnBuZyIpLCBkcGk9MzAwKQpgYGAKCgpOb3cgdGhhdCB3ZSBsZWFybmVkIHRoZSBiYXNpY3Mgb2YgZ2dwbG90LCBsZXQncyBkcmF3IHNvbWUgcGxvdCBmb3Igb3VyIGV4cGVyaW1lbnQgZGF0YS4gRmlyc3QsIHdlIG5lZWQgdG8gY3JlYXRlIGEgZGF0YXNldCB3aXRoIGFnZ3JlZ2F0ZWQgYHRydXRoIGVzdGltYXRlYCBzY29yZXMgb3ZlciBgZ3JvdXBgIGFuZCBgc3RhZ2VgLiBXZSB3aWxsIHVzZSB0aGlzIGRhdGFzZXQgZm9yIGxpbmUgYW5kIGJhciBncmFwaHMuCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZHBpPSAzMDAsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTV9CgphZ2dyZWdhdGVkX2RhdGFfZXhwMSA8LSBkYXRhX2V4cDEgJT4lCiAgZ3JvdXBfYnkoc3RhZ2UsIGdyb3VwKSAlPiUKICBtdXRhdGUodHJ1dGhfZXN0aW1hdGUgPSBtZWFuKHRydXRoX2VzdGltYXRlKSkgJT4lCiAgdW5ncm91cCgpCgpiYXJwbG90X2V4cDEgPC0gYWdncmVnYXRlZF9kYXRhX2V4cDEgJT4lCiAgZ2dwbG90KGFlcyh4PXN0YWdlLCB5PSB0cnV0aF9lc3RpbWF0ZSwgZmlsbD1ncm91cCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb249ICJkb2RnZSIpKwogICMgc3RhdF9zdW1tYXJ5KGZ1bj0gbWVhbiwgZ2VvbSA9ICJiYXIiLCBwb3NpdGlvbiA9ICJkb2RnZSIpKyAjIGNhbiBiZSB1c2VkIGluc3RlYWQgb2YgZ2VvbV9iYXIoKSBmb3IgbG9uZyBkYXRhZnJhbWVzCiAgbGFicyAoeD0gJycsIHk9ICJUcnV0aCBMaWtlbGloaG9kIEVzdGltYXRlIikgKyAKICB0aGVtZV9idygpICsgCiAgc2NhbGVfZmlsbF9qYW1hKCkgCgpiYXJwbG90X2V4cDEKCgpiYXJwbG90X2ZhY2V0X2V4cDEgPC0gYWdncmVnYXRlZF9kYXRhX2V4cDEgJT4lCiAgZ2dwbG90KGFlcyh4PWdyb3VwLCB5PSB0cnV0aF9lc3RpbWF0ZSwgZmlsbD1zdGFnZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb249ICJkb2RnZSIpKwogIGxhYnMgKHg9ICcnLCB5PSAiVHJ1dGggTGlrZWxpaGhvZCBFc3RpbWF0ZSIpICsgCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTEpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogIGZhY2V0X3dyYXAofnN0YWdlKSsKICBzY2FsZV9maWxsX2pjbygpIAoKYmFycGxvdF9mYWNldF9leHAxCgoKbGluZXBsb3RfZXhwMSA8LSBhZ2dyZWdhdGVkX2RhdGFfZXhwMSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZmFjdG9yKHN0YWdlKSwgeT0gdHJ1dGhfZXN0aW1hdGUsIGdyb3VwPSBncm91cCwgY29sb3I9IGdyb3VwKSkgKwogIGdlb21fbGluZShhZXMobGluZXR5cGU9IGdyb3VwKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0gNSkrCiAgbGFicyAoeD0gJycsIHk9ICJUcnV0aCBMaWtlbGloaG9kIEVzdGltYXRlIikgKyAKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMSksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgc2NhbGVfY29sb3JfbmVqbSgpIAoKbGluZXBsb3RfZXhwMQoKCnZpb2xpbnBsb3RfZXhwMSA8LSBkYXRhX2V4cDEgJT4lCiAgZ2dwbG90KGFlcyh4PWZhY3RvcihzdGFnZSksIHk9IHRydXRoX2VzdGltYXRlLCBmaWxsPSBncm91cCkpICsKICBnZW9tX3Zpb2xpbigpKwogIGxhYnMgKHg9ICcnLCB5PSAiVHJ1dGggTGlrZWxpaGhvZCBFc3RpbWF0ZSIpICsgCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMSksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgc2NhbGVfZmlsbF9kMygpIAoKdmlvbGlucGxvdF9leHAxCgoKYm94cGxvdF9leHAxIDwtIGRhdGFfZXhwMSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZmFjdG9yKHN0YWdlKSwgeT0gdHJ1dGhfZXN0aW1hdGUsIGZpbGw9IGdyb3VwKSkgKwogIGdlb21fYm94cGxvdCgpKwogICNnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MC43NSksIGFscGhhPSAuNSkrCiAgbGFicyAoeD0gJycsIHk9ICJUcnV0aCBMaWtlbGloaG9kIEVzdGltYXRlIikgKyAKICB0aGVtZV9idygpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTExKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICBzY2FsZV9maWxsX3NpbXBzb25zKCkgCgpib3hwbG90X2V4cDEKCgpib3hwbG90X2ZhY2V0X2V4cDEgPC0gZGF0YV9leHAxICU+JQogIGdncGxvdChhZXMoeD1mYWN0b3Ioc3RhZ2UpLCB5PSB0cnV0aF9lc3RpbWF0ZSwgZmlsbD0gZ3JvdXApKSArCiAgZ2VvbV9ib3hwbG90KCkrCiAgbGFicyAoeD0gJycsIHk9ICJUcnV0aCBMaWtlbGloaG9kIEVzdGltYXRlIikgKyAKICB0aGVtZV9idygpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTExKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgZmFjZXRfd3JhcCh+Z3JvdXApKwogIHNjYWxlX2NvbG9yX3NpbXBzb25zKCkgCgpib3hwbG90X2ZhY2V0X2V4cDEKCgpgYGAKCkhMZXQncyBjb21iaW5lIG91ciBwbG90czoKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNzAwcHgiLCBvdXQuaGVpZ2h0PSIzNTBweCIsIGZpZy5jYXA9ICJBcnR3b3JrIGJ5IEFsbGlzb24gSG9yc3Q6IGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3Qvc3RhdHMtaWxsdXN0cmF0aW9ucyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ3BhdGNod29ya18xLmpwZycpKQpgYGAKCmBgYHtyIGRwaT0gMzAwLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05fQoKY29tYmluZWRfcGxvdF9leHAxIDwtIChiYXJwbG90X2ZhY2V0X2V4cDErbGluZXBsb3RfZXhwMSkgLyAodmlvbGlucGxvdF9leHAxK2JveHBsb3RfZXhwMSkKY29tYmluZWRfcGxvdF9leHAxCmBgYAoKQW5kIGhlcmUsIHdlIHNhdmUgb3VyIHBsb3RzIHRvIHRoZSBgb3V0cHV0c2AgZm9sZGVyLgpgYGB7cm1lc3NhZ2U9Rn0KZ2dzYXZlKGNvbWJpbmVkX3Bsb3RfZXhwMSwgZmlsZW5hbWUgPSBoZXJlKCJvdXRwdXRzIiwiY29tYmluZWRfcGxvdF9leHAxLnBuZyIpLCBkcGk9MzAwKQpgYGAKCiMgRGF0YSBBbmFseXNpcwoKCiMjIHQtdGVzdAoKTm93LCB3ZSB1c2UgdGhlIHRyZWF0bWVudCBkYXRhIHRvIHJ1biB0aHJlZSBkaWZmZXJlbnQgaW5kZXBlbmRlbnQgdC10ZXN0cy4gU3VwcG9zZSB3ZSBkaWQgYW4gZXhwZXJpbWVudCB0byBjb21wYXJlIHRoZSBlZmZlY3RpdmVuZXNzIG9mIENCVCB2cy4gUHN5Y2hvZHluYW1pYyB0aGVyYXBpZXMgaW4gZGVjcmVhc2luZyBhbnhpZXR5LCBhbmQgZGVwcmVzc2lvbiBhbmQgYWxzbyBpbiBpbXByb3ZpbmcgbGlmZSBzYXRpc2ZhY3Rpb246CgpgYGB7cn0KIyB0LnRlc3QgKGluZGVwKQp0LnRlc3QoYW54aWV0eX50cmVhdG1lbnQsIGRhdGE9IHRyZWF0bWVudF9kYXRhKQp0LnRlc3QoZGVwcmVzc2lvbn50cmVhdG1lbnQsIGRhdGE9IHRyZWF0bWVudF9kYXRhKQp0LnRlc3QobGlmZV9zYXRpc2ZhY3Rpb25+dHJlYXRtZW50LCBkYXRhPSB0cmVhdG1lbnRfZGF0YSkKYGBgCgpJbiBhbm90aGVyIGV4cGVyaW1lbnQsIHN1cHBvc2Ugd2UgaGF2ZSBjcmVhdGVkIGEgbWV0aG9kIHRvIGJvb3N0IG1lbW9yeS4gVGhlbiwgd2UgcmVjcnVpdCBzb21lIHBhcnRpY2lwYW50cywgZG8gYSBtZW1vcnkgcHJlLXRlc3QsIGltcGxlbWVudCB0aGUgbWV0aG9kLCBhbmQgZG8gYSBtZW1vcnkgcG9zdC10ZXN0LCBOb3csIHdlIHdhbnQgdG8gc2VlIHdoZXRoZXIgb3VyIG1ldGhvZCBoYXZlIGltcHJvdmVkIHBhcnRpY2lwYW50cycgbWVtb3J5OiAKCmBgYHtyfQojIHQudGVzdCAocGFpcmVkKQp0LnRlc3QobWVtb3J5X3Njb3JlfnRpbWUsIGRhdGE9IG1lbW9yeV9kYXRhLCBwYWlyZWQ9IFQpCmBgYAoKTm93IHRoYXQgd2UgbGVhcm5lZCBhYm91dCB0LXRlc3QsIGxldCdzIHBlcmZvcm0gdGhpcyB0ZXN0IG9uIG91ciBkYXRhc2V0LiBJcyB0aGVyZSBhIGRpZmZlcmVuY2UgYmV0d2VlbiBncm91cHMgYXQgdGhlIGZpcnN0IHN0YWdlPyBJZGVhbGx5LCB3ZSB3YW50IHBhcnRpY2lwYW50cycgcmF0aW5ncyBhdCB0aGUgZmlyc3Qgc3RhZ2UgYmUgc2ltaWxhciBmb3IgYm90aCBncm91cHMgYmVjYXVzZSB3ZSBoYXZlIG5vdCBkb25lIGFueSBtYW5pcHVsYXRpb25zLiBQcmV2aW91cyBncmFwaHMgc2hvd2VkIHVzIHRoYXQgcmF0aW5ncyBvZiBzaW1wbGUgYW5kIGNvbXBsZXggZ3JvdXAgYXQgdGhpcyBzdGFnZSBhcmUgcHJldHR5IGNsb3NlLiBMZXQncyB0ZXN0IHRoYXQgdXNpbmcgYW4gKippbmRlcGVuZGVudCB0LXRlc3QqKiAoYmVjYXVzZSB3ZSBoYXZlIDIgaW5kZXBlbmRlbnQgZ3JvdXBzKToKCmBgYHtyfQojIElzIHRoZXJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIGdyb3VwcyBhdCB0aGUgZmlyc3Qgc3RhZ2U/CmRhdGFfZXhwMSAlPiUgCiAgZ3JvdXBfYnkoZ3JvdXApICU+JSAKICBmaWx0ZXIoc3RhZ2U9PSdzdGFnZTEnKSAlPiUgCiAgdW5ncm91cCAoKSAlPiUKICB0LnRlc3QodHJ1dGhfZXN0aW1hdGV+Z3JvdXAsIGRhdGEgPSAuLCBwYWlyZWQ9RkFMU0UpCmBgYAoKTm93LCB3ZSB3b25kZXIgaWYgb3Bwb3NpbmcgYXJndW1lbnRzIHdlcmUgZWZmZWN0aXZlIGF0IGFsbCwgcmVnYXJkbGVzcyBvZiBwYXJ0aWNpcGFudHMnIGdyb3VwLiBTbywgd2Ugd291bGQgbGlrZSB0byB0ZXN0IGlmIHJhdGluZ3MgYXQgdGhlIGZpbmFsIHN0YWdlIGFyZSBsb3dlciB0aGFuIHJhdGluZ3MgYXQgdGhlIHN0YWdlIDQ/IFNpbmNlIGEgcGFpciBvZiBzY29yZSBhdCBzdGFnZSA0IGFuZCBzdGFnZSA3IGlzIGNvbWluZyBmcm9tIGEgc2FtZSBwZXJzb24sIHdlIHVzZSAqKnBhaXJlZCB0LXRlc3QqKi4KCmBgYHtyfQojIElzIHRoZXJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHJhdGluZ3Mgb2Ygc3RhZ2U0IGFuZCBzdGFnZTc/CmRhdGFfZXhwMSAlPiUgCiAgZmlsdGVyKHN0YWdlPT0nc3RhZ2U0JyB8IHN0YWdlPT0nc3RhZ2U3JykgJT4lIAogIHVuZ3JvdXAgKCkgJT4lCiAgdC50ZXN0KHRydXRoX2VzdGltYXRlfnN0YWdlLCBkYXRhID0gLiwgcGFpcmVkPVRSVUUpCmBgYAoKCiMjIyBFeGVyY2lzZQoKSm9obiBldCBhbC4gKDIwMTkpIGludmVzdGlnYXRlZCB0aGUgY29uc2VxdWVuY2VzIG9mIGJhY2tpbmcgZG93biAoY2hhbmdpbmcgb25lJ3MgbWluZCBpbiBsaWdodHMgb2YgZXZpZGVuY2UpYW5kIGhvdyBvdGhlciBwZW9wbGUgdmlldyBzb21lb25lIHdobyBjaGFuZ2UgdGhlaXIgbWluZC4gSW4gdGhlaXIgc2Vjb25kIGV4cGVyaW1lbnRzLCB0aGV5IHByZXNlbnRlZCBwYXJ0aWNpcGFudHMgZWl0aGVyIHdpdGggYSBwZXJzb24gd2hvIGNoYW5nZXMgdGhlaXIgbWluZCBvciBhIHBlcnNvbiB3aG8gcmVmdXNlcyB0byBiYWNrIGRvd24uIFRoZW4sIHRoZXkgYXNrZWQgcGFydGljaXBhbnRzIHRvIHJhdGUgaG93IGludGVsbGlnZW50IGFuZCBjb25maWRlbnQgdGhlIHBlcnNvbiBpcyAoU2VlIHRoZSBvcmlnaW5hbCBzdHVkeSBbaGVyZV0oaHR0cHM6Ly93d3cuaGJzLmVkdS9mYWN1bHR5L1B1YmxpY2F0aW9uJTIwRmlsZXMvSm9obiUyMGV0JTIwYWwlMjAtJTIwc2VsZi1wcmVzZW50YXRpb25hbCUyMGNvbnNlcXVlbmNlc19iODViMmM0My1hNWI1LTQ3NGMtOWUyYy1lOTg1M2IxMDcyN2UucGRmKSkuIFRoZXkgcmVwb3J0ZWQgdGhhdDogCgo+ICJSZWxhdGl2ZSB0byB0aGUgZW50cmVwcmVuZXVyIHdobyBkaWQgbm90IGJhY2sgZG93biwgcGFydGljaXBhbnRzIGp1ZGdlZCB0aGUgZW50cmVwcmVuZXVyIHdobyBiYWNrZWQgZG93biBhcyBtb3JlIGludGVsbGlnZW50IChNX2JhY2tlZF9kb3duPTUuMTMgb3V0IG9mIDcsIFNEPTEuMDk7IE1fZGlkX25vdF9iYWNrX2Rvd249My45NywgU0Q9MS41NDsgdCgyNzEuMTIpPeKIkjcuNTksIHAgPCAuMDAxKSBidXQgbGVzcyBjb25maWRlbnQgKE1fYmFja2VkX2Rvd249NC41MCBvdXQgb2YgNywgU0Q9MS4zNjsgTV9kaWRfbm90X2JhY2tfZG93bj01LjY1LCBTRD0xLjEwOyB0KDI5MS4wMSk9OC4wOCwgcCA8IC4wMDEpLiIuCgpPcGVuIHRoZSBgam9obl9iYWNrZG93bl9leHAyLmNzdmAgZmlsZSBhbmQgdHJ5IHRvIHJlcHJvZHVjZSB0aGVpciByZXN1bHRzLiBSdW4gdHdvIHNlcGFyYXRlIGluZGVwZW5kZW50IHQtdGVzdCwgb25lIHdpdGggYGludGVsbGlnZW50YCBhcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBvbmUgd2l0aCBgY29uZmlkZW50YCBhcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLiBGb3IgYm90aCB0LXRlc3QsIHVzZSBgYmFja19kb3duYCBhcyB0aGUgYmV0d2Vlbi1zdWJqZWN0IGluZGVwZW5kZW50IHZhcmlhYmxlLgoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmpvaG5fZGF0YSA8LSByZWFkX2NzdihoZXJlKCJjbGVhbmVkX2RhdGEiLCJqb2huX2JhY2tkb3duX2V4cDIuY3N2IikpCgoKdC50ZXN0KGludGVsbGlnZW50fmJhY2tfZG93biwgZGF0YSA9IGpvaG5fZGF0YSwgcGFpcmVkPUZBTFNFKQp0LnRlc3QoY29uZmlkZW50fmJhY2tfZG93biwgZGF0YSA9IGpvaG5fZGF0YSwgcGFpcmVkPUZBTFNFKQpgYGAKCgojIyBBbmFseXNpcyBvZiBWYXJpYW5jZSAoQU5PVkEpCgpOb3csIGxldCdzIGFuc3dlciBvdXIgbWFpbiBxdWVzdGlvbjogRG8gcGFydGljaXBhbnRzIGluIHRoZSBzaW1wbGUgZ3JvdXAgc2hvdyBoaWdoZXIgcmF0aW5ncyBmb3Igc3VwcG9ydGl2ZSBhcmd1bWVudHMgKHN0YWdlIDIgdG8gNCkgYW5kIGxvd2VyIHJhdGluZ3MgZm9yIG9wcG9zaW5nIGFyZ3VtZW50cyAoc3RhZ2UgNSB0byA3KSwgY29tcGFyZWQgdG8gcGFydGljaXBhbnRzIGluIHRoZSBjb21wbGV4IGdyb3VwPyBJZiB0aGlzIGlzIHRoZSBjYXNlLiB3ZSBleHBlY3QgYW4gaW50ZXJhY3Rpb24gaW4gdGhlIHRyYWRpdGlvbmFsICoqQW5hbHlzaXMgb2YgVmFyaWFuY2UgKEFPTlZBKSoqIHRlc3QuCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KYW92X20xIDwtIGFvdl9jYXIgKHRydXRoX2VzdGltYXRlIH4gZ3JvdXAqc3RhZ2UgKwogICAgICAgICAgICAgICAgICAgICBFcnJvcihzdWJqZWN0L3N0YWdlKSwgZGF0YSA9IGRhdGFfZXhwMSkKYGBgCgpgYGB7ciBlY2hvPUZ9CmtuaXRyOjprYWJsZShuaWNlKGFvdl9tMSkpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiwgImNvbmRlbnNlZCIpLCBmaXhlZF90aGVhZCA9IFQsIGZ1bGxfd2lkdGggPSBUKQpgYGAKCkFzIHlvdSBjYW4gc2VlLCB3ZSBmb3VuZCBhIHNpZ25pZmljYW50IG1haW4gZWZmZWN0IG9mIHN0YWdlIGFuZCBhIHNpZ25pZmljYW50IGdyb3VwIGJ5IHN0YWdlIGludGVyYWN0aW9uLiBXZSBjYW4gdXNlIHRoZSBgZW1tZWFuc2AgcGFja2FnZSB0byBkbyBwb3N0LWhvYyB0ZXN0cy4KCmBgYHtyIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIG1haW4gZWZmZWN0IG9mIHN0YWdlCmVtbWVhbnMoYW92X20xLCAnc3RhZ2UnKQpwYWlycyhlbW1lYW5zKGFvdl9tMSwgJ3N0YWdlJyksIGFkanVzdD0gJ2hvbG0nKQpgYGAKCgpgYGB7ciB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBncm91cCBieSBzdGFnZSBpbnRlcmFjdGlvbgplbW1lYW5zKGFvdl9tMSwgImdyb3VwIiwgYnk9ICJzdGFnZSIpCnVwZGF0ZShwYWlycyhlbW1lYW5zKGFvdl9tMSwgImdyb3VwIiwgYnk9ICJzdGFnZSIpKSwgYnkgPSBOVUxMLCBhZGp1c3QgPSAiaG9sbSIpIApgYGAKCllvdSBjYW4gdXNlIHRoZSBgYWZleF9wbG90YCBmdW5jdGlvbiBmcm9tIGFmZXggdG8gY3JlYXRlIGJlYXV0aWZ1bCBwbG90cy4gVGhvc2UgcGxvdHMgaW50ZXJhY3RzIG5pY2VseSB3aXRoIGdncGxvdDoKYGBge3IgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGRwaT0gMzAwfQphZmV4X3Bsb3QoYW92X20xLCB4ID0gInN0YWdlIiwgdHJhY2UgPSAiZ3JvdXAiLCBlcnJvcj0nYmV0d2VlbicsCiAgICAgICAgICBsaW5lX2FyZyA9IGxpc3Qoc2l6ZT0xKSwKICAgICAgICAgIHBvaW50X2FyZyA9IGxpc3Qoc2l6ZT0zLjUpLAogICAgICAgICAgZGF0YV9hcmcgPSBsaXN0KHNpemU9IDEsIGNvbG9yPSAnZ3JleScsIHdpZHRoPS40KSwKICAgICAgICAgIGRhdGFfZ2VvbSA9IGdlb21fYm94cGxvdCwKICAgICAgICAgIG1hcHBpbmcgPSBjKCJsaW5ldHlwZSIsICJzaGFwZSIsICJmaWxsIiksCiAgICAgICAgICBsZWdlbmRfdGl0bGUgPSAiR3JvdXAiKSArCiAgbGFicyh5ID0gIlRydXRoIExpa2VsaWhob2QgRXN0aW1hdGUiLCB4ID0gIiIpICsKICB0aGVtZV9idygpKyAjIHJlbW92ZSB0aGUgZ3JleSBiYWNrZ3JvdW5kIGFuZCBncmlkCiAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTMpLAogICAgICAgIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgImNtIiksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gJ2JsYWNrJywgZmlsbCA9ICd3aGl0ZScsIGxpbmV0eXBlPSdzb2xpZCcpKSsKICBzY2FsZV9jb2xvcl9zaW1wc29ucygpICsKICBzY2FsZV9maWxsX3NpbXBzb25zKCkKYGBgCgoKSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIHRoaXMgdG9waWMsIGNoZWNrIG91dCB0aGlzIG5pY2UgdHV0b3JpYWwgYWJvdXQgW3VzaW5nIGFmZXggdG8gcnVuIEFOT1ZBXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvYWZleC92aWduZXR0ZXMvYWZleF9hbm92YV9leGFtcGxlLmh0bWwpLCBhbmQgYWxzbyB0aGlzIGludGVyZXN0aW5nIHR1dG9yaWFsIG9uIHRoZSBbZW1tZWFucyBwYWNrYWdlXShodHRwczovL2Fvc21pdGgucmJpbmQuaW8vMjAxOS8wMy8yNS9nZXR0aW5nLXN0YXJ0ZWQtd2l0aC1lbW1lYW5zLykuCgojIyMgRXhlcmNpc2UKClJvdGVsbG8gZXQgYWwuICgyMDE4KSBpbnZlc3RpZ2F0ZWQgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIHJhY2UgKFdoaXRlIHZzLiBCbGFjayBmYWNlcykgYW5kIHRoZSBndW4tdG9vbCBqdWRnbWVudHMuIEluIHRoZWlyIGZpcnN0IGV4cGVyaW1lbnRzLCB0aGV5IHByZXNlbnRlZCBwYXJ0aWNpcGFudHMgd2l0aCAxNiBXaGl0ZSBtYWxlIGZhY2VzIGFuZCAxNiBCbGFjayBtYWxlIGZhY2VzLCBhbmQgZm9sbG93aW5nIHRoYXQgOCBpbWFnZXMgb2YgZ3VucyBhbmQgOCBpbWFnZXMgb2YgdG9vbHMuIFRoZXkgYXNrZWQgcGFydGljaXBhbnRzIHRvIGp1ZGdlIGlmIHRoZSBvYmplY3QgaXMgYSB0b29sIG9yIGEgZ3VuIGJ5IHByZXNzaW5nIGtleWJvYXJkIGJ1dHRvbnMuIFRoZW4sIHRoZXkgcmFuIGFuIEFOT1ZBIHRvIHNlZSBpZiBwYXJ0aWNpcGFudHMnIGd1biByZXNwb25zZXMgYXJlIGhpZ2hlciBmb3IgYW55IG9mIHRoZSByYWNlcy4gU28sIHRoZXkgaW5jbHVkZWQgcHJpbWUgcmFjZSAoQmxhY2ssIFdoaXRlKSBhbmQgdGFyZ2V0IGlkZW50aXR5IChndW4sIHRvb2wpIGFzIGluZGVwZW5kZW50IHZhcmlhYmxlcyBhbmQgcGFydGljaXBhbnRzJyBndW4gcmVzcG9uc2VzIGFzIGRlcGVuZGVudCB2YXJpYWJsZSBpbnRvIHRoZWlyIGxpbmVhciBtb2RlbCAoU2VlIHRoZSBvcmlnaW5hbCBzdHVkeSBbaGVyZV0oaHR0cHM6Ly9vbmxpbmUudWNwcmVzcy5lZHUvY29sbGFicmEvYXJ0aWNsZS80LzEvMzIvMTEyOTg2L1RoZS1TaGFwZS1vZi1ST0MtQ3VydmVzLWluLVNob290ZXItVGFza3MpKS4gVGhleSBmb3VuZCB0aGF0OiAKCj4gIlBhcnRpY2lwYW50cyBtYWRlIG1vcmUgZ3VuIHJlc3BvbnNlcyB0byBndW5zIHRoYW4gdG8gdG9vbHMsIEYoMSw0NSkgPSA1MzI0MywgcCA8IDAuMDAwMSwgzrcyZyA9IDAuOTk4LiBIb3dldmVyLCB0aGUgcmFjZSBvZiB0aGUgcHJpbWUgZmFjZSBkaWQgbm90IG1hdHRlciwgRigxLDQ1KSA9IDAuMjg3LCBwID4gMC41OSwgzrcyZyA9IDAuMDAxLCBub3Igd2FzIHRoZXJlIGFuIGludGVyYWN0aW9uIG9mIHByaW1lIHJhY2Ugd2l0aCB0YXJnZXQgb2JqZWN0LCBGKDEsNDUpID0gMC4wMjIsIHAgPiAwLjg4LCDOtzJnID0gMC4wMDApIi4KCk9wZW4gdGhlIGByb3RlbGxvX3Nob290ZXJfZXhwMS5jc3ZgIGZpbGUgYW5kIHRyeSB0byByZXByb2R1Y2UgdGhlaXIgcmVzdWx0cy4gUnVuIGFuIEFOT1ZBICh0eXBlIElJSSkgd2l0aCBgcmVzcGAgYXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBhbmQgdGFyZ2V0LCBwcmltZSwgYW5kIHRoZWlyIGludGVyYWN0aW9uIGFzIGluZGVwZW5kZW50IHZhcmlhYmxlcy4KCgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KIyBsb2FkIHRoZSBnZW5lcmFsIGRhdGEgZmlsZQpyb3RlbGxvX2RhdGEgPC0gcmVhZF9jc3YoaGVyZSgiY2xlYW5lZF9kYXRhIiwicm90ZWxsb19zaG9vdGVyX2V4cDEuY3N2IikpCgojIEFOT1ZBCnJvdGVsbG9fYW92IDwtIGFvdl9jYXIgKHJlc3AgfiB0YXJnZXQqcHJpbWUgKwogICAgICAgICAgIEVycm9yKHN1YmplY3QvdGFyZ2V0KnByaW1lKSwgZGF0YSA9IHJvdGVsbG9fZGF0YSkKYGBgCgpgYGB7ciBlY2hvPUZ9CmtuaXRyOjprYWJsZShuaWNlKHJvdGVsbG9fYW92KSkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IFQpCmBgYAoKCgojIyBDb3JyZWxhdGlvbgoKSGVyZSwgd2Ugd2FudCB0byBjaGVjayB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB2YXJpYWJsZXMgb24gdGhlIGBuYXJjaXNzaXNtX2RhdGFgLiBGaXJzdCwgd2UgbmVlZCB0byByZW1vdmUgYHN1YmplY3RgIGNvbHVtbiBiZWNhdXNlIGl0IGlzIG5vdCBudW1lcmljOgpgYGB7ciBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KbmFyY2lzc2lzbV9kYXRhX2NvciA8LSBuYXJjaXNzaXNtX2RhdGEgJT4lCiAgc2VsZWN0KC1zdWJqZWN0KQpgYGAKCmBgYHtyIG1lc3NhZ2U9RiwgZXZhbD1GLCBmaWcuYWxpZ249J2NlbnRlcicsIGRwaT0zMDB9CgojLS0gQmFzZSBSOgpjb3IobmFyY2lzc2lzbV9kYXRhX2NvciwgbWV0aG9kID0gInBlYXJzb24iLCAgdXNlID0gImNvbXBsZXRlLm9icyIpCgojLS0gUHN5Y2ggbGlicmFyeToKcHN5Y2g6OnBhaXJzLnBhbmVscyhuYXJjaXNzaXNtX2RhdGFfY29yLCBtZXRob2QgPSAicGVhcnNvbiIsIGhpc3QuY29sID0gIiMwMEFGQkIiLCBkZW5zaXR5ID0gVCwgZWxsaXBzZXMgPSBGLCBzdGFycyA9IFQpCgojLS0gQ29ycmVsYXRpb24gbGlicmFyeToKIyBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJlYXN5c3RhdHMvY29ycmVsYXRpb24iKQojbGlicmFyeSgiY29ycmVsYXRpb24iKQpjb3JyZWxhdGlvbjo6Y29ycmVsYXRpb24obmFyY2lzc2lzbV9kYXRhX2NvcikgJT4lIHN1bW1hcnkoKQoKIy0tIGFwYVRhYmxlcyBsaWJyYXJ5OgpuYXJjaXNzaXNtX2RhdGFfY29yICU+JSAKICBhcGFUYWJsZXM6OmFwYS5jb3IudGFibGUoZmlsZW5hbWU9Ii4vb3V0cHV0cy9Db3JNYXRyaXguZG9jIiwgc2hvdy5jb25mLmludGVydmFsPVQpCmBgYAoKYGBge3IgbWVzc2FnZT1GLCBlY2hvPUYsIGZpZy5hbGlnbj0nY2VudGVyJywgZHBpPTMwMH0KCiMtLSBCYXNlIFI6CmNvcihuYXJjaXNzaXNtX2RhdGFfY29yLCBtZXRob2QgPSAicGVhcnNvbiIsICB1c2UgPSAiY29tcGxldGUub2JzIiklPiUKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IEYpCgojLS0gUHN5Y2ggbGlicmFyeToKcHN5Y2g6OnBhaXJzLnBhbmVscyhuYXJjaXNzaXNtX2RhdGFfY29yLCBtZXRob2QgPSAicGVhcnNvbiIsIGhpc3QuY29sID0gIiMwMEFGQkIiLCBkZW5zaXR5ID0gVCwgZWxsaXBzZXMgPSBGLCBzdGFycyA9IFQpCgojLS0gQ29ycmVsYXRpb24gbGlicmFyeToKIyBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJlYXN5c3RhdHMvY29ycmVsYXRpb24iKQojbGlicmFyeSgiY29ycmVsYXRpb24iKQpjb3JyZWxhdGlvbjo6Y29ycmVsYXRpb24obmFyY2lzc2lzbV9kYXRhX2NvcikgJT4lIHN1bW1hcnkoKSU+JQogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgZml4ZWRfdGhlYWQgPSBULCBmdWxsX3dpZHRoID0gRikKCmBgYAoKCk5vdyB0aGF0IHdlIGxlYXJuZWQgYWJvdXQgY29ycmVsYXRpb24gdGVzdCwgbGV0J3MgYW5zd2VyIHRvIGFub3RoZXIgcXVlc3Rpb24gb2YgdGhpcyBzdHVkeTogZG9lcyBwZXJzdWFzaW9uIGFuZCBkaXNzdWFzaW9uIGlzIHJlbGF0ZWQgdG8gb3Blbi1taW5kZWRuZXNzLCBjb2duaXRpdmUgYWJpbGl0eSwgcmVhc29uaW5nIGFiaWxpdGllcywgYW5kIHRoaW5raW5nIHN0eWxlPyBUbyBhbnN3ZXIgdGhpcyBxdWVzdGlvbiwgd2UgbmVlZCB0byBjcmVhdGUgdHdvIGluZGV4ZXMgKHNjb3Jlcykgb25lIGZvciBwZXJzdWFzaW9uIGFuZCBvbmUgZm9yIGRpc3N1YXNpb24uIFRoZW4gd2UgY2FuIGRvIGEgY29ycmVsYXRpb24gdGVzdDoKCmBgYHtyIG1lc3NhZ2U9RiwgZXZhbD1GLCBmaWcuYWxpZ249J2NlbnRlcicsIGRwaT0zMDB9Cgpjb3JfZGF0YV9leHAxIDwtIGRhdGFfZXhwMSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHN0YWdlLCB2YWx1ZXNfZnJvbSA9IHRydXRoX2VzdGltYXRlKSAlPiUKICBncm91cF9ieShzdWJqZWN0KSAlPiUKICBtdXRhdGUocGVyc3Vhc2lvbl9pbmRleD0gc3RhZ2UyKyBzdGFnZTMrIHN0YWdlNCAtIHN0YWdlMSwKICAgICAgICAgZGlzc3Vhc2lvbl9pbmRleD0gKDEwMS1zdGFnZTUpICsgKDEwMS1zdGFnZTYpICsgKDEwMS1zdGFnZTcpIC0gKDEwMS1zdGFnZTQpKSAlPiUKICB1bmdyb3VwKCklPiUKICBkcGx5cjo6c2VsZWN0KHBlcnN1YXNpb25faW5kZXgsZGlzc3Vhc2lvbl9pbmRleCxvcGVubWluZGVkX3RvdGFsLG51bWVyYWN5X3RvdGFsLHRoaW5raW5nX3RvdGFsLHJlYXNvbmluZ190b3RhbCkKCiMtLS0tLS0tLS0tIEJhc2UgUjoKY29yKGNvcl9kYXRhX2V4cDEsIG1ldGhvZCA9ICJwZWFyc29uIiwgIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKIy0tLS0tLS0tLS0gUHN5Y2ggbGlicmFyeToKY29yX2RhdGFfZXhwMSAlPiUgCiAgcHN5Y2g6OnBhaXJzLnBhbmVscyhtZXRob2QgPSAicGVhcnNvbiIsIGhpc3QuY29sID0gIiMwMEFGQkIiLCBkZW5zaXR5ID0gVCwgZWxsaXBzZXMgPSBGLCBzdGFycyA9IFQpCgojLS0tLS0tLS0tLSBDb3JyZWxhdGlvbiBsaWJyYXJ5Ogpjb3JyZWxhdGlvbjo6Y29ycmVsYXRpb24oY29yX2RhdGFfZXhwMSkgJT4lIHN1bW1hcnkoKQoKIy0tLS0tLS0tLS0gYXBhVGFibGVzIGxpYnJhcnk6CmNvcl9kYXRhX2V4cDEgJT4lIAogIGFwYVRhYmxlczo6YXBhLmNvci50YWJsZShmaWxlbmFtZT0iLi9vdXRwdXRzL0Nvck1hdHJpeC5kb2MiLCBzaG93LmNvbmYuaW50ZXJ2YWw9VCkKYGBgCgpgYGB7ciBtZXNzYWdlPUYsIGVjaG89RiwgZmlnLmFsaWduPSdjZW50ZXInLCBkcGk9MzAwfQpjb3JfZGF0YV9leHAxIDwtIGRhdGFfZXhwMSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHN0YWdlLCB2YWx1ZXNfZnJvbSA9IHRydXRoX2VzdGltYXRlKSAlPiUKICBncm91cF9ieShzdWJqZWN0KSAlPiUKICBtdXRhdGUocGVyc3Vhc2lvbl9pbmRleD0gc3RhZ2UyKyBzdGFnZTMrIHN0YWdlNCAtIHN0YWdlMSwKICAgICAgICAgZGlzc3Vhc2lvbl9pbmRleD0gKDEwMS1zdGFnZTUpICsgKDEwMS1zdGFnZTYpICsgKDEwMS1zdGFnZTcpIC0gKDEwMS1zdGFnZTQpKSAlPiUKICB1bmdyb3VwKCklPiUKICBkcGx5cjo6c2VsZWN0KHBlcnN1YXNpb25faW5kZXgsZGlzc3Vhc2lvbl9pbmRleCxvcGVubWluZGVkX3RvdGFsLG51bWVyYWN5X3RvdGFsLHRoaW5raW5nX3RvdGFsLHJlYXNvbmluZ190b3RhbCkKCiMtLS0tLS0tLS0tIEJhc2UgUjoKY29yKGNvcl9kYXRhX2V4cDEsIG1ldGhvZCA9ICJwZWFyc29uIiwgIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSU+JQogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgZml4ZWRfdGhlYWQgPSBULCBmdWxsX3dpZHRoID0gRiklPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjc4MHB4IikKCiMtLS0tLS0tLS0tIFBzeWNoIGxpYnJhcnk6CmNvcl9kYXRhX2V4cDEgJT4lIAogIHBzeWNoOjpwYWlycy5wYW5lbHMobWV0aG9kID0gInBlYXJzb24iLCBoaXN0LmNvbCA9ICIjMDBBRkJCIiwgZGVuc2l0eSA9IFQsIGVsbGlwc2VzID0gRiwgc3RhcnMgPSBUKQoKIy0tLS0tLS0tLS0gQ29ycmVsYXRpb24gbGlicmFyeToKY29ycmVsYXRpb246OmNvcnJlbGF0aW9uKGNvcl9kYXRhX2V4cDEpICU+JSBzdW1tYXJ5KCklPiUKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IEYpJT4lCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICI3ODBweCIpCgpgYGAKCgojIyMgRXhlcmNpc2UKClBlbm55Y29vayBldCBhbC4gKDIwMjApIGludmVzdGlnYXRlZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYWN0aXZlbHkgb3Blbi1taW5kZWQgdGhpbmtpbmcgc3R5bGUgYWJvdXQgZXZpZGVuY2UgKEFPVC1FKSBhbmQgZGlmZmVyZW50IHBvbGl0aWNhbCwgc2NpZW50aWZpYywgYW5kIHJlbGlnaW91cyBiZWxpZWZzIChzZWUgdGhlIG9yaWdpbmFsIHBhcGVyIFtoZXJlXShodHRwczovL3BzeWFyeGl2LmNvbS9hN2s5NikpLiBJbiB0aGVpciBmaXJzdCBleHBlcmltZW50LCB0aGV5IGNhbGN1bGF0ZWQgdGhlIGNvcnJlbGF0aW9uIG9mIEFPVEUgYW5kIHNjaWVudGlmaWMgYmVsaWVmcyBpdGVtcyAoZ2xvYmFsIHdhcm1pbmcsIGV2b2x1dGlvbiwgZXRjLikgYW5kIHRoZXkgZm91bmQgdGhlIGZvbGxvd2luZyByZXN1bHRzOgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI3MDBweCIsIG91dC5oZWlnaHQ9IjM1MHB4IiwgZmlnLmNhcD0gImFkYXB0ZWQgZnJvbSBbUGVubnljb29rIGV0IGFsLiAoMjAyMCldKGh0dHBzOi8vcHN5YXJ4aXYuY29tL2E3azk2KSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ3Blbm55Y29va19jb3JyLnBuZycpKQpgYGAKCk9wZW4gdGhlIGBwZW5ueWNvb2tfYW90ZV9leHAxLmNzdmAgZmlsZSBhbmQgdHJ5IHRvIHJlcHJvZHVjZSB0aGVpciByZXN1bHRzIGJ5IGNyZWF0aW5nIHRoZSBzYW1lIGNvcnJlbGF0aW9uIG1hdHJpeC4KCmBgYHtyIG1lc3NhZ2U9RiwgZXZhbD1GfQpwZW5ueWNvb2tfZGF0YSA8LSByZWFkX2NzdihoZXJlKCJjbGVhbmVkX2RhdGEiLCJwZW5ueWNvb2tfYW90ZV9leHAxLmNzdiIpKSAKCgojLS0tLS0tLS0tLSBCYXNlIFI6CmNvcihwZW5ueWNvb2tfZGF0YSwgbWV0aG9kID0gInBlYXJzb24iLCAgdXNlID0gImNvbXBsZXRlLm9icyIpCgojLS0tLS0tLS0tLSBQc3ljaCBsaWJyYXJ5OgpwZW5ueWNvb2tfZGF0YSAlPiUgCiAgcHN5Y2g6OnBhaXJzLnBhbmVscyhtZXRob2QgPSAicGVhcnNvbiIsIGhpc3QuY29sID0gIiMwMEFGQkIiLCBkZW5zaXR5ID0gVCwgZWxsaXBzZXMgPSBGLCBzdGFycyA9IFQpCgojLS0tLS0tLS0tLSBDb3JyZWxhdGlvbiBsaWJyYXJ5Ogpjb3JyZWxhdGlvbjo6Y29ycmVsYXRpb24ocGVubnljb29rX2RhdGEpICU+JSBzdW1tYXJ5KCkKCiMtLS0tLS0tLS0tIGFwYVRhYmxlcyBsaWJyYXJ5OgpwZW5ueWNvb2tfZGF0YSAlPiUgCiAgYXBhVGFibGVzOjphcGEuY29yLnRhYmxlKGZpbGVuYW1lPSIuL291dHB1dHMvQ29yTWF0cml4LmRvYyIsIHNob3cuY29uZi5pbnRlcnZhbD1UKQpgYGAKCgpgYGB7ciBtZXNzYWdlPUYsIGV2YWw9VCwgZWNobz1GLCBmaWcuYWxpZ249J2NlbnRlcicsIGRwaT0zMDB9CnBlbm55Y29va19kYXRhIDwtIHJlYWRfY3N2KGhlcmUoImNsZWFuZWRfZGF0YSIsInBlbm55Y29va19hb3RlX2V4cDEuY3N2IikpICU+JQogIGNsZWFuX25hbWVzKCkKCmNvcnJlbGF0aW9uOjpjb3JyZWxhdGlvbihwZW5ueWNvb2tfZGF0YSkgJT4lIHN1bW1hcnkoKSAlPiUKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IEYpJT4lCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICI3ODBweCIpCgpgYGAKCgojIyBMaW5lYXIgUmVncmVzc2lvbgoKSGVyZSwgd2UgZG8gc2luZ2xlIGFuZCBtdWx0aXBsZSBsaW5lYXIgcmVncmVhc3Npb24gb24gdGhlIGBuYXJjaXNzaXNtX2RhdGFgOgoKYGBge3J9Cm0xIDwtIGxtKG1lbnRhbF9oZWFsdGh+bmFyY2lzc2lzbSwgZGF0YT0gbmFyY2lzc2lzbV9kYXRhKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RiwgZXZhbD1ULCBlY2hvPUYsIGZpZy5hbGlnbj0nY2VudGVyJywgZHBpPTMwMH0KYnJvb206OnRpZHkobTEpJT4lCiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiwgImNvbmRlbnNlZCIpLCBmaXhlZF90aGVhZCA9IFQsIGZ1bGxfd2lkdGggPSBUKQpgYGAKCmBgYHtyfQptMiA8LSBsbShtZW50YWxfaGVhbHRofm5hcmNpc3Npc20rcHN5Y2hvcGF0aHksIGRhdGE9IG5hcmNpc3Npc21fZGF0YSkKYGBgCgpgYGB7ciBtZXNzYWdlPUYsIGV2YWw9VCwgZWNobz1GLCBmaWcuYWxpZ249J2NlbnRlcicsIGRwaT0zMDB9CmJyb29tOjp0aWR5KG0yKSU+JQogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAyKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgZml4ZWRfdGhlYWQgPSBULCBmdWxsX3dpZHRoID0gVCkKYGBgCgpOb3csIGxldCdzIHBlcmZvcm0gcmVncmVzc2lvbiBhbmFseXNlcyBvbiBvdXIgb3duIGRhdGFzZXQuIEluIHRoZSBwcmV2aW91cyBzZWN0aW9uLCB3ZSBmb3VuZCB0aGF0IG9wZW4tbWluZGVkbmVzcyAoQU9ULUUpIGlzIGNvcnJlbGF0ZWQgd2l0aCBwZXJzdWFzaW9uLiBOb3csIG9uZSBtYXkgYXNrIGlmIG9wZW4tbWluZGVkbmVzcyBjYW4gcHJlZGljdCBwZXJzdWFzaW9uIGFmdGVyIGNvbnRyb2xsaW5nIGZvciByZWFzb25pbmcgYW5kIGNvbnRyb2xsaW5nIGFiaWxpdGllcz8gVG8gYW5zd2VyIHRoYXQsIHdlIGNhbiBydW4gYSBtdWx0aXBsZSByZWdyZXNzaW9uIGFuYWx5c2lzOgpgYGB7cn0KZXhwMV9yZWc9bG0ocGVyc3Vhc2lvbl9pbmRleCB+IG9wZW5taW5kZWRfdG90YWwrIG51bWVyYWN5X3RvdGFsKyB0aGlua2luZ190b3RhbCsgcmVhc29uaW5nX3RvdGFsLAogICAgICAgICAgICAgICAgICBkYXRhPWNvcl9kYXRhX2V4cDEpCmBgYAoKYGBge3IgbWVzc2FnZT1GLCBldmFsPVQsIGVjaG89RiwgZmlnLmFsaWduPSdjZW50ZXInLCBkcGk9MzAwfQpicm9vbTo6dGlkeShleHAxX3JlZyklPiUKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IFQpCmBgYAoKIyMjIEV4ZXJjaXNlCgpUcsOpbW9sacOocmUgYW5kIERqZXJpb3VhdCAoMjAyMCkgZXhhbWluZWQgdGhlIHJvbGUgb2YgKmNvZ25pdGl2ZSByZWZsZWN0aW9uKiBhbmQgKmJlbGllZiBpbiBzY2llbmNlKiBpbiBjbGltYXRlIGNoYW5nZSBza2VwdGljaXNtLiBJbiB0aGVpciBmaXJzdCBzdHVkeSwgdGhleSByZXZlYWxlZCB0aGF0IGNvZ25pdGl2ZSByZWZsZWN0aW9uIGFuZCBiZWxpZWYgaW4gc2NpZW5jZSBuZWdldGl2ZWx5IHByZWRpY3RlZCBjbGltYXRlIGNoYW5nZSBza2VwdGljaXNtIGV2ZW4gYWZ0ZXIgY29udHJvbGxpbmcgZm9yIGRlbW9ncmFwaGljIGFuZCBjb2duaXRpdmUgYWJpbGl0eSB2YXJpYWJsZXMgKHNlZSB0aGUgb3JpZ2luYWwgcGFwZXIgW2hlcmVdKGh0dHBzOi8vcHN5YXJ4aXYuY29tL3ZwOGs2LykpLiAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNzAwcHgiLCBvdXQuaGVpZ2h0PSIzNTBweCIsIGZpZy5jYXA9ICJhZGFwdGVkIGZyb20gW1Ryw6ltb2xpw6hyZSBhbmQgRGplcmlvdWF0ICgyMDIwKV0oaHR0cHM6Ly9wc3lhcnhpdi5jb20vdnA4azYvKSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ3RyZW1vbGllcmVfcmVnLnBuZycpKQpgYGAKCk9wZW4gdGhlIGB0cmVtb2xpZXJlX2RhdGFfZXhwMS5jc3ZgIGZpbGUgYW5kIHRyeSB0byByZXByb2R1Y2UgdGhlaXIgcmVzdWx0cyBieSBydW5uaW5nIGEgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24uIEVudGVyIGFnZSwgZ2VuZGVyLCBlZHVjYXRpb24sIGJlbGllZiBpbiBzY2llbmNlLCBsaXRlcmFjeSwgbnVtZXJhY3kgKE51bXRvdGFsKSwgYW5kIGNvZ25pdGl2ZSByZWZsZWN0aW9uIGFzIHByZWRpY3RvcnMgYW5kIGVudGVyIGNsaW1hdGUgY2hhbmdlIHNrZXB0aWNpc20gKGNsaW1hdG8pIGFzIHRoZSBvdXRjb21lIHZhcmlhYmxlLgoKYGBge3IgbWVzc2FnZT1GfQpUcmVtb2xpZXJlX2RhdGEgPC0gcmVhZF9jc3YoaGVyZSgiY2xlYW5lZF9kYXRhIiwidHJlbW9saWVyZV9kYXRhX2V4cDEuY3N2IikpCgpUcmVtb2xpZXJlX3JlZz1sbShDbGltYXRvIH4gQWdlKyBHZW5kZXIrIEVkdWNhdGlvbisgQmVsaWVmSW5TY2llbmNldG90YWwrIExpdGVyYWN5KyBOdW10b3RhbCsgQ29nbml0aXZlUmVmbGVjdGlvbiwKICAgICAgICAgICAgICAgICAgICBkYXRhPVRyZW1vbGllcmVfZGF0YSkKYGBgCgoKYGBge3IgbWVzc2FnZT1GLCBldmFsPVQsIGVjaG89RiwgZmlnLmFsaWduPSdjZW50ZXInLCBkcGk9MzAwfQpicm9vbTo6dGlkeShUcmVtb2xpZXJlX3JlZyklPiUKICBrbml0cjo6a2FibGUoZGlnaXRzID0gMikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIGZpeGVkX3RoZWFkID0gVCwgZnVsbF93aWR0aCA9IFQpCgpnbGFuY2UoVHJlbW9saWVyZV9yZWcpJT4lCiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiwgImNvbmRlbnNlZCIpLCBmaXhlZF90aGVhZCA9IFQsIGZ1bGxfd2lkdGggPSBGKSU+JQogIHNjcm9sbF9ib3god2lkdGggPSAiNzgwcHgiKQpgYGAKCgojIFJtYXJrZG93bgoKVG8gYmUgY29tcGxldGVkLi4uCgoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPSI3MDBweCIsIG91dC5oZWlnaHQ9IjM1MHB4IiwgZmlnLmNhcD0gIkFydHdvcmsgYnkgQWxsaXNvbiBIb3JzdDogaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9zdGF0cy1pbGx1c3RyYXRpb25zIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgnaW5wdXRzJywncm1hcmtkb3duX3dpemFyZHMucG5nJykpCmBgYAoKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNzAwcHgiLCBvdXQuaGVpZ2h0PSIzNTBweCIsIGZpZy5jYXA9ICJBcnR3b3JrIGJ5IEFsbGlzb24gSG9yc3Q6IGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3Qvc3RhdHMtaWxsdXN0cmF0aW9ucyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoJ2lucHV0cycsJ3JlcHJvZHVjaWJpbGl0eV9jb3VydC5wbmcnKSkKYGBgCgojIFJlZmVyZW5jZXMKCi0gR2hhc2VtaSwgTy4sIEhhbmRsZXksIFMuLCAmIEhvd2FydGgsIFMuICgyMDIwKS4gVGhlIEJyaWdodCBIb211bmN1bHVzIGluIG91ciBIZWFkOiBJbmRpdmlkdWFsIERpZmZlcmVuY2VzIGluIEludHVpdGl2ZSBTZW5zaXRpdml0eSB0byBMb2dpY2FsIFZhbGlkaXR5LgoKLSBKb2huLCBMLiBLLiwgSmVvbmcsIE0uLCBHaW5vLCBGLiwgJiBIdWFuZywgTC4gKDIwMTkpLiBUaGUgc2VsZi1wcmVzZW50YXRpb25hbCBjb25zZXF1ZW5jZXMgb2YgdXBob2xkaW5nIG9uZeKAmXMgc3RhbmNlIGluIHNwaXRlIG9mIHRoZSBldmlkZW5jZS4gT3JnYW5pemF0aW9uYWwgQmVoYXZpb3IgYW5kIEh1bWFuIERlY2lzaW9uIFByb2Nlc3NlcywgMTU0LCAxLTE0LgoKLSBQZW5ueWNvb2ssIEcuLCBDaGV5bmUsIEouIEEuLCBLb2VobGVyLCBELiBKLiwgJiBGdWdlbHNhbmcsIEouIEEuICgyMDIwKS4gT24gdGhlIGJlbGllZiB0aGF0IGJlbGllZnMgc2hvdWxkIGNoYW5nZSBhY2NvcmRpbmcgdG8gZXZpZGVuY2U6IEltcGxpY2F0aW9ucyBmb3IgY29uc3BpcmF0b3JpYWwsIG1vcmFsLCBwYXJhbm9ybWFsLCBwb2xpdGljYWwsIHJlbGlnaW91cywgYW5kIHNjaWVuY2UgYmVsaWVmcy4gSnVkZ21lbnQgYW5kIERlY2lzaW9uIE1ha2luZywgMTUoNCksIDQ3Ni4KCi0gUm90ZWxsbywgQy4gTS4sIEtlbGx5LCBMLiBKLiwgSGVpdCwgRS4sIFZhemlyZSwgUy4sICYgVnVsLCBFLiAoMjAxOCkuIFRoZSBTaGFwZSBvZiBST0MgQ3VydmVzIGluIFNob290ZXIgVGFza3M6IEltcGxpY2F0aW9ucyBmb3IgQmVzdCBQcmFjdGljZXMgaW4gQW5hbHlzaXMuIENvbGxhYnJhOiBQc3ljaG9sb2d5LCA0KDEpLgoKLSBUcsOpbW9sacOocmUsIEIuLCAmIERqZXJpb3VhdCwgSC4gKDIwMjApLiBEb27igJl0IHlvdSBzZWUgdGhhdCBpdHMgY29sZCEgRXhwbG9yaW5nIHRoZSByb2xlcyBvZiBjb2duaXRpdmUgcmVmbGVjdGlvbiwgY2xpbWF0ZSBzY2llbmNlIGxpdGVyYWN5LCBpbGx1c2lvbiBvZiBrbm93bGVkZ2UsIGFuZCBwb2xpdGljYWwgb3JpZW50YXRpb24gaW4gY2xpbWF0ZSBjaGFuZ2Ugc2tlcHRpY2lzbS4KCi0gV2lja2hhbSwgSC4gKDIwMTQpLiBUaWR5IGRhdGEuIEpvdXJuYWwgb2YgU3RhdGlzdGljYWwgU29mdHdhcmUsIDU5KDEwKSwgMS0yMy4=